diff --git a/.github/workflows/release-preview.yml b/.github/workflows/release-preview.yml index 66032cb7ca..f806e3471e 100644 --- a/.github/workflows/release-preview.yml +++ b/.github/workflows/release-preview.yml @@ -100,6 +100,22 @@ concurrency: cancel-in-progress: false env: + # Workspace Team's four vela transports are gated in the packaged runtime on + # BOTH a known AMR profile and a non-empty vela web origin + # (workspaceTeamTransportEnv in apps/packaged/src/workspace-team.ts). Neither + # has a default in tools-pack, so a lane that omits them ships a client whose + # team features are silently dormant: the build succeeds, the app starts, and + # the gap only shows up in a user's hands. + # + # Unlike beta/prerelease these are production channels, so the profile is + # pinned rather than taken from an input — there is no legitimate stable or + # preview build aimed at the test backend. Naming prod explicitly is a no-op + # for AMR itself (apps/daemon/src/integrations/vela-profile.ts already + # defaults to prod); it exists to satisfy the first half of the gate. A fork + # or PR build without the secret leaves the origin empty, which keeps the + # transports dormant rather than half-enabled. + OPEN_DESIGN_AMR_PROFILE: prod + OD_VELA_WEB_URL: ${{ secrets.VELA_WEB_URL_PROD }} OPEN_DESIGN_TELEMETRY_RELAY_URL: ${{ vars.OPEN_DESIGN_TELEMETRY_RELAY_URL }} # PostHog product-analytics ingest. Defined as repository secret + var # so official builds ship with analytics enabled; PR builds and forks diff --git a/.github/workflows/release-stable.yml b/.github/workflows/release-stable.yml index 76e61dcb06..880283ac5b 100644 --- a/.github/workflows/release-stable.yml +++ b/.github/workflows/release-stable.yml @@ -119,6 +119,22 @@ concurrency: cancel-in-progress: false env: + # Workspace Team's four vela transports are gated in the packaged runtime on + # BOTH a known AMR profile and a non-empty vela web origin + # (workspaceTeamTransportEnv in apps/packaged/src/workspace-team.ts). Neither + # has a default in tools-pack, so a lane that omits them ships a client whose + # team features are silently dormant: the build succeeds, the app starts, and + # the gap only shows up in a user's hands. + # + # Unlike beta/prerelease these are production channels, so the profile is + # pinned rather than taken from an input — there is no legitimate stable or + # preview build aimed at the test backend. Naming prod explicitly is a no-op + # for AMR itself (apps/daemon/src/integrations/vela-profile.ts already + # defaults to prod); it exists to satisfy the first half of the gate. A fork + # or PR build without the secret leaves the origin empty, which keeps the + # transports dormant rather than half-enabled. + OPEN_DESIGN_AMR_PROFILE: prod + OD_VELA_WEB_URL: ${{ secrets.VELA_WEB_URL_PROD }} OPEN_DESIGN_TELEMETRY_RELAY_URL: ${{ vars.OPEN_DESIGN_TELEMETRY_RELAY_URL }} # PostHog product-analytics ingest. Defined as repository secret + var # so official builds ship with analytics enabled; PR builds and forks diff --git a/tools/pack/tests/release-workflows.test.ts b/tools/pack/tests/release-workflows.test.ts index 96904f122b..01d3750797 100644 --- a/tools/pack/tests/release-workflows.test.ts +++ b/tools/pack/tests/release-workflows.test.ts @@ -394,6 +394,40 @@ describe("release workflows", () => { expect(stablePrepare).toContain('setOutput("publish_side_effects_enabled"'); }); + it("bakes both halves of the workspace-team gate into every shipping lane", async () => { + const [beta, preview, prerelease, stable] = await Promise.all([ + readFile(new URL("../../../.github/workflows/release-beta.yml", import.meta.url), "utf8"), + readFile(new URL("../../../.github/workflows/release-preview.yml", import.meta.url), "utf8"), + readFile(new URL("../../../.github/workflows/release-prerelease.yml", import.meta.url), "utf8"), + readFile(new URL("../../../.github/workflows/release-stable.yml", import.meta.url), "utf8"), + ]); + + // workspaceTeamTransportEnv (apps/packaged/src/workspace-team.ts) enables the + // four vela transports only when a known AMR profile AND a non-empty vela web + // origin are both baked in. A lane that bakes neither still builds, still + // installs, and still starts — the gap only surfaces as "Workspace Team does + // nothing" once a package reaches a user. So the presence of both halves is + // asserted per lane rather than left to the packaging step to notice. + for (const workflow of [beta, preview, prerelease, stable]) { + expect(workflow).toContain("OPEN_DESIGN_AMR_PROFILE:"); + expect(workflow).toContain("OD_VELA_WEB_URL:"); + } + + // beta and prerelease are validation lanes and stay dispatch-driven, so an + // operator can aim a build at feature-test or test. + expect(beta).toContain("OPEN_DESIGN_AMR_PROFILE: ${{ inputs.amr_profile }}"); + expect(prerelease).toContain("OPEN_DESIGN_AMR_PROFILE: ${{ inputs.amr_profile }}"); + + // preview and stable are production channels by definition. Pinning the pair + // instead of accepting an input removes the footgun of publishing a stable + // build wired to the test backend — there is no legitimate reason for one. + for (const workflow of [preview, stable]) { + expect(workflow).toContain("OPEN_DESIGN_AMR_PROFILE: prod"); + expect(workflow).toContain("OD_VELA_WEB_URL: ${{ secrets.VELA_WEB_URL_PROD }}"); + expect(workflow).not.toContain("inputs.amr_profile"); + } + }); + it("passes launcher version floor repo vars through to metadata publish and verify verbatim", async () => { const [beta, betaSelfHosted, preview, prerelease, stable] = await Promise.all([ readFile(new URL("../../../.github/workflows/release-beta.yml", import.meta.url), "utf8"),