Skip to content

fix(release): pin host Deno to bundled canary so denort matches#1308

Merged
stack72 merged 1 commit intomainfrom
fix/release-canary-host-deno
May 5, 2026
Merged

fix(release): pin host Deno to bundled canary so denort matches#1308
stack72 merged 1 commit intomainfrom
fix/release-canary-host-deno

Conversation

@stack72
Copy link
Copy Markdown
Contributor

@stack72 stack72 commented May 5, 2026

Summary

Stop shipping a swamp CLI with the buggy denort-2.7.14 runtime baked in. Resolve the pinned canary SHA from the existing single source of truth (scripts/deno_canary.txt) and use it as the host Deno for deno compile, so denort is fetched from dl.deno.land/canary/<sha>/ instead of release/v2.7.14/.

Why the swamp-club deploy still panics on the latest release

The current stable swamp tarball was built with this release flow:

  1. denoland/setup-deno@v2 with deno-version: v2.x — installs stable 2.7.14.
  2. scripts/compile.ts downloads canary 19bd3d8b and writes it to resources/deno/deno ✅.
  3. deno compile --include resources/deno --output dist/swamp-linux-x86_64 main.ts — runs under 2.7.14, so it pulls https://dl.deno.land/release/v2.7.14/denort-x86_64-unknown-linux-gnu.zip and bakes that into the swamp CLI binary.

Result: the shipped swamp binary contains two runtimes:

  • denort-2.7.14 — runs main.ts (the swamp CLI / workflow runner). Still has the ext/node/ops/tls_wrap.rs:2018 unwrap.
  • canary-19bd3d8b (the embedded resource) — extracted to ~/.swamp/deno and used by spawned children, not by the CLI process.

The TLS panic the swamp-club deploy hits comes from the workflow runner uploading to giga-swamp.sfo3.digitaloceanspaces.com — that runs in the swamp CLI process (single PID 2467 throughout the failing log), i.e. in denort-2.7.14. So the embedded canary resource doesn't help here.

Verified: denort-{x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu, x86_64-apple-darwin, aarch64-apple-darwin, x86_64-pc-windows-msvc}.zip are all present at dl.deno.land/canary/19bd3d8b99d92f15d20692aca02ac059bbc9ada7/ (HTTP 200 for all five), so deno compile will be able to fetch them on every target.

Change

  • release.yml: new Resolve Deno canary SHA step reads scripts/deno_canary.txt (same parsing as readCanarySha() in scripts/download_deno.ts) and pins denoland/setup-deno@v2's deno-version to canary-<sha>. Marked CANARY-BRIDGE for grep-ability.
  • deno_canary.txt: back-out checklist now lists the release.yml step to remove when v2.8.0 ships.

Other workflows (publish-testing.yml, publish-client.yml, ci.yml) don't run deno compile, so they don't bake denort and are intentionally left on stable.

Test plan

  • Merge → release runs → confirm log shows Pinned Deno canary: 19bd3d8b... and the subsequent deno compile fetches denort from dl.deno.land/canary/19bd3d8b.../denort-...zip (not release/v2.7.14/).
  • Re-run the swamp-club Deploy swamp-club to DigitalOcean workflow on the new stable swamp; the S3 upload to DigitalOcean Spaces should complete without the tls_wrap.rs:2018:31 panic.
  • swamp --version on the new build still reports the expected swamp version string.

🤖 Generated with Claude Code

`deno compile` bakes the host deno's matching `denort-<version>` into the
compiled binary as the runtime that executes `main.ts` — i.e. the swamp
CLI itself, including the workflow runner that does TLS uploads. The
release job was running `deno compile` under stable v2.x (currently
2.7.14), which embeds `denort-2.7.14` containing the unfixed
ext/node/ops/tls_wrap.rs unwrap (denoland/deno#33713). The fact that
scripts/download_deno.ts also embeds the patched canary as a resource at
resources/deno/deno doesn't help: that copy is extracted to ~/.swamp/deno
for spawned children, not used by the CLI process where the panic fires.

Resolve the pinned SHA from scripts/deno_canary.txt (the existing single
source of truth) and pass it to denoland/setup-deno, so `denort` is
fetched from dl.deno.land/canary/<sha>/ instead of release/v2.7.14/.
The bridge is grep-able via `CANARY-BRIDGE` and the back-out checklist
now lists the workflow change to undo when v2.8.0 ships.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

No blocking issues found. This is a clean, well-scoped fix for the denort version mismatch that caused TLS panics in production.

What I verified

  1. SHA parsing consistency — The shell pipeline in the workflow (grep -v comments | grep -v blank | head -n1 | tr -d space) correctly mirrors the readCanarySha() logic in scripts/download_deno.ts. Both skip #-comment and blank lines, taking the first content line.
  2. Error handling — Empty SHA is caught with an explicit error message and exit 1 before the workflow proceeds.
  3. Back-out checklist — Correctly updated and renumbered with the new step 3 for the workflow change.
  4. CANARY-BRIDGE markers — Consistently applied across the workflow comment and step, making cleanup grep-able.
  5. Security — SHA is read from a repo-committed file, not from untrusted PR input. Full 40-char pinned hash, not a mutable ref.
  6. Scope — Only the release workflow is changed; other workflows (ci.yml, publish-testing.yml, publish-client.yml) are correctly left on stable since they don't run deno compile.

LGTM — ship it.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CI Security Review

Critical / High

None.

Medium

  1. denoland/setup-deno@v2 (release.yml:49) — tag-only pin, not SHA-pinned. Pre-existing, not introduced by this PR. If a compromised v2 tag were pushed, the release job (which has contents: write and access to UAT_TRIGGER_TOKEN) would execute attacker-controlled setup code. Consider pinning to a full SHA for parity with softprops/action-gh-release and peter-evans/repository-dispatch, which are already SHA-pinned. Same applies to several Docker actions in the docker job (docker/setup-qemu-action@v3, docker/build-push-action@v6, etc.) — also pre-existing.

Low

None.

Verdict

PASS. The new "Resolve Deno canary SHA" step reads a committed file from ref: main, outputs a deterministic hash, and passes it via steps.canary.outputs.sha into a with: input — no expression injection, no shell injection, no new secret exposure. The deno_canary.txt changes are documentation-only (updated back-out checklist numbering). No security concerns introduced by this PR.

@stack72 stack72 merged commit d50f46e into main May 5, 2026
12 checks passed
@stack72 stack72 deleted the fix/release-canary-host-deno branch May 5, 2026 16:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant