mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
fix: production CSP blocking PostHog/Sentry/Scalar and silent failure hardening
The production CSP had connect-src/script-src/font-src set to 'self' only, silently blocking all analytics and error reporting in production while working fine in dev (where CSP is not applied). CSP fixes: - Add PostHog ingest + assets origins to connect-src and script-src - Add Sentry ingest origin to connect-src - Add Scalar fonts origin to font-src for API docs pages - Extract CSP construction into testable buildCsp() function Silent failure hardening: - Settings/features stores now set loadError flag and allow retry on subsequent fetch() calls instead of permanently caching failed state - Analytics init no longer sets initialized=true before the try block, allowing retry on failure - Settings dialog Tools section disables save button when settings failed to load, preventing accidental config wipe - Branding logo storage moved from process.cwd() to FILES_STORAGE_PATH so logos persist across Docker container recreation Test coverage: - 16 CSP directive tests covering all external service domains - Store retry-on-error behavior tests for settings and features stores - Analytics init retry-after-failure test
This commit is contained in:
@@ -16,12 +16,10 @@ function scrubString(str: string): string {
|
||||
|
||||
export async function initAnalytics(config: AnalyticsConfig): Promise<void> {
|
||||
if (initialized || !config.enabled) return;
|
||||
initialized = true;
|
||||
|
||||
try {
|
||||
const posthogJs = (await import("posthog-js")).default;
|
||||
if (!consentGranted) {
|
||||
initialized = false;
|
||||
return;
|
||||
}
|
||||
posthog =
|
||||
@@ -39,15 +37,15 @@ export async function initAnalytics(config: AnalyticsConfig): Promise<void> {
|
||||
ip: false,
|
||||
persistence: "localStorage",
|
||||
}) ?? null;
|
||||
} catch {
|
||||
// SDK blocked or unavailable
|
||||
initialized = true;
|
||||
} catch (err) {
|
||||
console.warn("[analytics] PostHog init failed:", err);
|
||||
}
|
||||
|
||||
try {
|
||||
if (config.sentryDsn) {
|
||||
const Sentry = await import("@sentry/react");
|
||||
if (!consentGranted) {
|
||||
initialized = false;
|
||||
return;
|
||||
}
|
||||
Sentry.init({
|
||||
@@ -86,8 +84,8 @@ export async function initAnalytics(config: AnalyticsConfig): Promise<void> {
|
||||
},
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
// Sentry blocked or unavailable
|
||||
} catch (err) {
|
||||
console.warn("[analytics] Sentry init failed:", err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user