From 25b9a3f9e2640c4b06b0a0abc5c95400613c5c91 Mon Sep 17 00:00:00 2001 From: Evie Gauthier Date: Thu, 9 Jul 2026 08:00:43 -0400 Subject: [PATCH 1/4] Verify Sentry release artifact workflow --- SENTRY.md | 25 +++++++ .../sentryReleaseArtifactsWorkflow.test.ts | 69 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 src/observability/sentryReleaseArtifactsWorkflow.test.ts diff --git a/SENTRY.md b/SENTRY.md index 970800d8..b93a355e 100644 --- a/SENTRY.md +++ b/SENTRY.md @@ -108,6 +108,31 @@ bundle shape as shipped releases. Manual runs can override the Sentry release name and environment; tag runs default the release name to the tag, and manual runs without a release input default to the commit SHA. +Owner-side manual verification can be run from a checkout with GitHub access: + +```sh +gh workflow run sentry-release-artifacts.yml \ + --ref main \ + -f release=manual-sentry-artifact-smoke-$(git rev-parse --short HEAD) \ + -f environment=production +``` + +Before dispatching, verify the repository has `SENTRY_AUTH_TOKEN`, +`SENTRY_ORG`, `SENTRY_PROJECT`, and `VITE_SENTRY_DSN` configured as Actions +secrets. After the run completes, verify in Sentry that: + +- the selected release exists and has frontend sourcemaps/artifacts uploaded; +- an intentional frontend stack frame symbolicates to source instead of built + `dist` chunks; +- Linux, macOS, Windows, and current iOS simulator debug files appear under + Debug Files with source context where supported; +- Android ProGuard/R8 mapping and native symbol uploads completed for the + release artifact build; +- Android Size Analysis has a build for the selected release/run, with the + expected base SHA comparison; +- GitHub uploaded the frontend, Linux, Apple, Windows, and Android size-report + artifacts for auditability. + Sentry Size Analysis currently receives Android builds only. The current iOS CI path builds an unsigned simulator debug app, while Sentry accepts XCArchive or IPA inputs for iOS size analysis; wire that upload once a signed device-release diff --git a/src/observability/sentryReleaseArtifactsWorkflow.test.ts b/src/observability/sentryReleaseArtifactsWorkflow.test.ts new file mode 100644 index 00000000..f868806c --- /dev/null +++ b/src/observability/sentryReleaseArtifactsWorkflow.test.ts @@ -0,0 +1,69 @@ +import { readFileSync } from "node:fs"; +import { resolve } from "node:path"; +import { describe, expect, it } from "vitest"; + +describe("Sentry release artifact workflow", () => { + const root = resolve(__dirname, "../.."); + const workflow = readFileSync( + resolve(root, ".github/workflows/sentry-release-artifacts.yml"), + "utf8", + ); + const viteConfig = readFileSync(resolve(root, "vite.config.ts"), "utf8"); + const releaseEnvScript = readFileSync( + resolve(root, ".github/scripts/configure-sentry-release-env.sh"), + "utf8", + ); + const androidAppBuild = readFileSync( + resolve(root, "src-tauri/gen/android/app/build.gradle.kts"), + "utf8", + ); + + it("keeps manual release and environment inputs available", () => { + expect(workflow).toContain("workflow_dispatch:"); + expect(workflow).toMatch(/release:\n\s+description: "Sentry release name\./); + expect(workflow).toMatch(/environment:\n\s+description: "Sentry environment tag/); + expect(workflow).toContain("default: production"); + }); + + it("requires Sentry owner secrets before upload jobs run", () => { + for (const secret of ["SENTRY_AUTH_TOKEN", "SENTRY_ORG", "SENTRY_PROJECT", "VITE_SENTRY_DSN"]) { + expect(workflow).toContain(`secrets.${secret}`); + } + + expect(releaseEnvScript).toContain("required=(SENTRY_AUTH_TOKEN SENTRY_ORG SENTRY_PROJECT)"); + expect(releaseEnvScript).toContain("required+=(VITE_SENTRY_DSN)"); + expect(releaseEnvScript).toContain("Missing required Sentry secret(s)"); + }); + + it("uploads frontend sourcemaps only from explicit Sentry release builds", () => { + expect(workflow).toContain('WRITE_FRONTEND_UPLOAD_ENV: "true"'); + expect(releaseEnvScript).toContain("SENTRY_UPLOAD=true"); + expect(viteConfig).toContain('procEnv.SENTRY_UPLOAD === "true"'); + expect(viteConfig).toContain( + "SENTRY_UPLOAD=true requires SENTRY_AUTH_TOKEN, SENTRY_ORG, and SENTRY_PROJECT", + ); + expect(viteConfig).toContain('sourcemaps: { filesToDeleteAfterUpload: ["dist/**/*.map"] }'); + expect(workflow).toContain("Sentry sourcemap upload left .map files in dist"); + }); + + it("uploads desktop and Apple debug files with source context and release debuginfo", () => { + expect(workflow).toContain('WRITE_RUST_DEBUG_ENV: "true"'); + expect(releaseEnvScript).toContain("CARGO_PROFILE_RELEASE_DEBUG=1"); + expect(workflow).toMatch(/pnpm dlx @sentry\/cli@3\.5\.1 debug-files upload/); + expect(workflow).toContain("--include-sources"); + expect(workflow).toContain("--wait"); + expect(workflow).toContain("pnpm tauri build"); + expect(workflow).toContain("pnpm tauri ios build --target aarch64-sim --debug --ci"); + }); + + it("keeps Android mapping, native-symbol, and size-analysis uploads wired", () => { + expect(workflow).toContain('SENTRY_ANDROID_UPLOAD: "true"'); + expect(workflow).toContain("pnpm tauri android build --ci"); + expect(androidAppBuild).toContain('System.getenv("SENTRY_ANDROID_UPLOAD") == "true"'); + expect(androidAppBuild).toContain("autoUploadProguardMapping.set(true)"); + expect(androidAppBuild).toContain("autoUploadNativeSymbols.set(true)"); + expect(androidAppBuild).toContain("includeNativeSources.set(true)"); + expect(workflow).toContain("pnpm dlx @sentry/cli@3.5.1 build upload"); + expect(workflow).toContain("--base-sha"); + }); +}); From 4a8e607596c1618825eaad56aea7b329d5fff7bf Mon Sep 17 00:00:00 2001 From: Evie Gauthier Date: Thu, 9 Jul 2026 08:06:15 -0400 Subject: [PATCH 2/4] Address Sentry release workflow test review --- src/observability/sentryReleaseArtifactsWorkflow.test.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/observability/sentryReleaseArtifactsWorkflow.test.ts b/src/observability/sentryReleaseArtifactsWorkflow.test.ts index f868806c..0c38d1b7 100644 --- a/src/observability/sentryReleaseArtifactsWorkflow.test.ts +++ b/src/observability/sentryReleaseArtifactsWorkflow.test.ts @@ -3,7 +3,7 @@ import { resolve } from "node:path"; import { describe, expect, it } from "vitest"; describe("Sentry release artifact workflow", () => { - const root = resolve(__dirname, "../.."); + const root = process.cwd(); const workflow = readFileSync( resolve(root, ".github/workflows/sentry-release-artifacts.yml"), "utf8", @@ -42,7 +42,8 @@ describe("Sentry release artifact workflow", () => { expect(viteConfig).toContain( "SENTRY_UPLOAD=true requires SENTRY_AUTH_TOKEN, SENTRY_ORG, and SENTRY_PROJECT", ); - expect(viteConfig).toContain('sourcemaps: { filesToDeleteAfterUpload: ["dist/**/*.map"] }'); + expect(viteConfig).toContain("filesToDeleteAfterUpload"); + expect(viteConfig).toContain("dist/**/*.map"); expect(workflow).toContain("Sentry sourcemap upload left .map files in dist"); }); From 20a06e7b17f805ab90a171b9998e1d69c7a95684 Mon Sep 17 00:00:00 2001 From: Evie Gauthier Date: Thu, 9 Jul 2026 08:16:58 -0400 Subject: [PATCH 3/4] Address Sentry workflow secret contract review --- src/observability/sentryReleaseArtifactsWorkflow.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/observability/sentryReleaseArtifactsWorkflow.test.ts b/src/observability/sentryReleaseArtifactsWorkflow.test.ts index 0c38d1b7..484b5638 100644 --- a/src/observability/sentryReleaseArtifactsWorkflow.test.ts +++ b/src/observability/sentryReleaseArtifactsWorkflow.test.ts @@ -36,6 +36,7 @@ describe("Sentry release artifact workflow", () => { }); it("uploads frontend sourcemaps only from explicit Sentry release builds", () => { + expect(workflow).toContain('REQUIRE_VITE_SENTRY_DSN: "true"'); expect(workflow).toContain('WRITE_FRONTEND_UPLOAD_ENV: "true"'); expect(releaseEnvScript).toContain("SENTRY_UPLOAD=true"); expect(viteConfig).toContain('procEnv.SENTRY_UPLOAD === "true"'); From cf12e22b2c28b8e0c033f745e5efb4ad398fd65f Mon Sep 17 00:00:00 2001 From: Evie Gauthier Date: Thu, 9 Jul 2026 08:20:52 -0400 Subject: [PATCH 4/4] Make Sentry workflow assertions CRLF safe --- src/observability/sentryReleaseArtifactsWorkflow.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/observability/sentryReleaseArtifactsWorkflow.test.ts b/src/observability/sentryReleaseArtifactsWorkflow.test.ts index 484b5638..4f4a0df3 100644 --- a/src/observability/sentryReleaseArtifactsWorkflow.test.ts +++ b/src/observability/sentryReleaseArtifactsWorkflow.test.ts @@ -20,8 +20,8 @@ describe("Sentry release artifact workflow", () => { it("keeps manual release and environment inputs available", () => { expect(workflow).toContain("workflow_dispatch:"); - expect(workflow).toMatch(/release:\n\s+description: "Sentry release name\./); - expect(workflow).toMatch(/environment:\n\s+description: "Sentry environment tag/); + expect(workflow).toMatch(/release:\r?\n\s+description: "Sentry release name\./); + expect(workflow).toMatch(/environment:\r?\n\s+description: "Sentry environment tag/); expect(workflow).toContain("default: production"); });