mirror of
https://github.com/hanzoai/o11y.git
synced 2026-10-15 12:58:33 +00:00
o11y is a self-hosted observability tool that was phoning home to three
third-party SaaS vendors with our users' data — inherited from the upstream
fork and, worse, enabled by DEFAULT: vite.config.ts gated each on
`env.VITE_X_ENABLED !== 'false'` (opt-OUT), so any operator who never set the
vars shipped all three. index.html injected two vendor <script> tags on every
page load, and AppRoutes HMAC-hashed the logged-in user's email to identify
them to the support-chat vendor.
Removed end to end:
- Go: web.Settings/SettingsConfig drop the three trackers, their configs,
defaults, and the O11Y_WEB_SETTINGS_* env surface.
- Schema: docs/config/web-settings.json declares only sentry;
types/generated/webSettings.ts regenerated from it (not hand-edited).
- Frontend: both vendor <script> loaders deleted from index.html; vite
defines, env types, example.env, window typings and widget styles gone.
The identify + theme/bubble effects in AppRoutes go with them, along with
the now-dead crypto-js Hex/HmacSHA256 and useIsDarkMode imports, and a
useEffect that existed only to compute the widget's feature-flag gates.
Support chat is now Hanzo Chat, native and one way: utils/supportChat.ts
exposes a single openSupportChat(); the three inline widget call sites
(SideNav, Support, LaunchChatSupport) all route through it. It delegates to
the existing openInNewTab helper rather than calling window.open itself —
the repo's own o11y/no-raw-absolute-path rule mandates that helper.
openInNewTab now passes `noopener`. window.open, unlike <a target="_blank">,
does not imply it, so all 57 call sites were leaving the opened tab able to
navigate us via window.opener (reverse tabnabbing). No caller can be affected:
the function returns void.
Sentry stays — it is our own fork (hanzoai/sentry), and it is now opt-IN
(`=== 'true'`) rather than opt-out.
Also drops two pre-existing dead references that the lint gate surfaced in
the touched files: an unused brand-logo import in SideNav and an empty
`declare interface Window {}` in global.d.ts (the real Window augmentation
lives in typings/window.ts — now the only one).
Verified: go test ./pkg/web/... ok (web + routerweb); tsgo --noEmit clean;
oxlint 0 errors; zero vendor references and zero outbound vendor script
loads remain.
Co-authored-by: Hanzo Dev <[email protected]>
85 lines
2.2 KiB
Go
85 lines
2.2 KiB
Go
package web
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/hanzoai/o11y/pkg/config"
|
|
"github.com/hanzoai/o11y/pkg/config/envprovider"
|
|
"github.com/hanzoai/o11y/pkg/factory"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestNewWithEnvProvider(t *testing.T) {
|
|
t.Setenv("O11Y_WEB_ENABLED", "false")
|
|
|
|
conf, err := config.New(
|
|
context.Background(),
|
|
config.ResolverConfig{
|
|
Uris: []string{"env:"},
|
|
ProviderFactories: []config.ProviderFactory{
|
|
envprovider.NewFactory(),
|
|
},
|
|
},
|
|
[]factory.ConfigFactory{
|
|
NewConfigFactory(),
|
|
},
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
actual := &Config{}
|
|
err = conf.Unmarshal("web", actual)
|
|
require.NoError(t, err)
|
|
|
|
def := NewConfigFactory().New().(*Config)
|
|
|
|
expected := &Config{
|
|
Enabled: false,
|
|
Index: def.Index,
|
|
Directory: def.Directory,
|
|
Settings: def.Settings,
|
|
}
|
|
|
|
assert.Equal(t, expected, actual)
|
|
}
|
|
|
|
func TestSettingsConfigWithEnvProvider(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
env string
|
|
value string
|
|
expected SettingsConfig
|
|
}{
|
|
{name: "sentry_enabled", env: "O11Y_WEB_SETTINGS_SENTRY_ENABLED", value: "true", expected: SettingsConfig{Sentry: SentryConfig{Enabled: true}}},
|
|
{name: "sentry_dsn", env: "O11Y_WEB_SETTINGS_SENTRY_DSN", value: "https://[email protected]/0", expected: SettingsConfig{Sentry: SentryConfig{DSN: "https://[email protected]/0"}}},
|
|
{name: "sentry_tunnel", env: "O11Y_WEB_SETTINGS_SENTRY_TUNNEL", value: "https://example.com/tunnel", expected: SettingsConfig{Sentry: SentryConfig{Tunnel: "https://example.com/tunnel"}}},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
t.Setenv(testCase.env, testCase.value)
|
|
|
|
conf, err := config.New(
|
|
context.Background(),
|
|
config.ResolverConfig{
|
|
Uris: []string{"env:"},
|
|
ProviderFactories: []config.ProviderFactory{
|
|
envprovider.NewFactory(),
|
|
},
|
|
},
|
|
[]factory.ConfigFactory{
|
|
NewConfigFactory(),
|
|
},
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
actual := &Config{}
|
|
err = conf.Unmarshal("web", actual)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, testCase.expected, actual.Settings)
|
|
})
|
|
}
|
|
}
|