Skip to content

promote master → production: shadow-canary 0.5.0 - #19

Merged
gtko merged 6 commits into
productionfrom
master
Apr 24, 2026
Merged

promote master → production: shadow-canary 0.5.0#19
gtko merged 6 commits into
productionfrom
master

Conversation

@gtko

@gtko gtko commented Apr 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Promotes `master` to `production` to ship the `@dotworld/shadow-canary-core` 0.5.0 upgrade (PR #18).

What ships

No breaking changes — Edge Config key unchanged, middleware contract unchanged, `/api/slo` unchanged. Normal canary ramp is safe.

After merge

  1. `deploy-prod.yml` fires, promotes shadow → prod, starts canary ramp (0% → step 4 → … per `STEP=4`).
  2. Next `canary-ramp.yml` tick (15min cron) uses the 0.5.0 workflow with the carried-over bypass; 500-char SLO body excerpts will start landing in the ring buffer.
  3. `/admin` reflects new UI: Shadow history list + configurable step input.

Test plan

  • Production deploy succeeds
  • `/api/slo` returns 200 on new prod
  • `/admin` renders "Shadow deploys récents" (starts with the migrated `deploymentDomainShadowPrevious` as 1st entry)
  • MANUEL step input 1-50 relabels buttons
  • Next canary tick: SLO ring buffer gets entries with 500-char body excerpts

🤖 Generated with Claude Code

gtko and others added 6 commits April 24, 2026 10:05
Vercel Deployment Protection intercepts raw *.vercel.app deploy URLs with
HTTP 401 "Authentication Required" by default. The SLO check in
canary-ramp.yml has to curl the raw prod deploy URL (we need per-deployment
routing for the canary model — a production alias would point at exactly one
version at a time), so without a bypass every check fails and the workflow
rolls back the canary to 0% every 15 min.

Observed before this fix:
  SLO check 1 → HTTP 401 :: <!doctype html>...<title>Authentication Required
  SLO check 2 → HTTP 401 :: ...
  → ok=0 → rollback to 0%

Fix:
- Read VERCEL_AUTOMATION_BYPASS_SECRET from repo secrets (already set via
  `gh secret set`).
- When the secret is present, send `x-vercel-protection-bypass: <SECRET>` on
  the SLO curl. This is the official Vercel bypass mechanism, documented at
  https://vercel.com/docs/deployment-protection/methods-to-bypass-deployment-protection.
- Fall through cleanly (no header) when the secret is unset, so projects that
  disable protection aren't forced to set a dummy secret.

Verified manually: same URL that returned 401 now returns 200 with
`{"ok":true,"deployment":"...","commit":"4474bd7","branch":"production"}`.

Note: this patch is local to Stargaze. The same issue affects any project that
uses @dotworld/shadow-canary-templates workflows with Vercel Deployment
Protection enabled — worth upstreaming into the templates package so new
adopters don't hit the silent-rollback trap.

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

fix(canary): send Vercel Deployment Protection bypass on SLO check
The "Record SLO check in Edge Config (ring buffer, last 10)" step injects
step outputs into the shell script via ${{ steps.slo.outputs.body_excerpt }},
which GitHub Actions substitutes as raw text (not shell-escaped). The body
excerpt starts with `{"ok":true,...` — those embedded `"` characters break
the surrounding "…" shell string and the script fails to parse:

  /home/runner/work/_temp/....sh: line 34: unexpected EOF while looking for
  matching `"'
  ##[error]Process completed with exit code 2.

Observed on the first run after enabling the Vercel bypass (run 24879157669):
SLO check itself returned 200, bump landed, ring-buffer record step crashed.

Fix: pass step outputs through the step's `env` block instead of ${{ }}
substitution. GitHub properly escapes env values, so `$SLO_BODY_EXCERPT`
stays intact regardless of its content. Also fixes the symmetric (latent)
issue on code1/code2/pct even though those currently hold digits only —
safer to keep them all on the same path.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
fix(canary): escape JSON body in SLO record step via env
Bumps @dotworld/shadow-canary-core from 0.4.0 to 0.5.0.

New in this release:
- /api/admin/shadow-history        — returns last 20 shadow deploys with
                                     sha/ref/message/time (fetched on-demand
                                     from the Vercel API, not stored inline)
- Admin UI "Shadow deploys récents" scrollable list, each row with a
  Rollback button. Current shadow gets a "current" badge.
- Admin MANUEL section: configurable step input (1-50). Buttons relabel to
  -N% / +N% live as the input changes.
- deploy-shadow.yml now prepends the outgoing shadow URL to a shadowHistory
  ring buffer (max 20, deduped), replacing the single-slot
  deploymentDomainShadowPrevious field. The old field is still written
  (points at shadowHistory[0]) so a v0.4.x admin UI mid-deploy does not
  break.
- Ring-buffer SLO body_excerpt trim bumped 80 to 500 chars so failures show
  the full JSON / truncated stack.

Local patches re-applied on top of the templates copy:
- Vercel Deployment Protection bypass on the SLO curl (VERCEL_AUTOMATION_BYPASS_SECRET).
- SLO-ring-buffer step outputs passed through env block to avoid shell quote
  injection on JSON body_excerpt. Both were merged as PR #16 and #17 on
  v0.4.x; neither is upstream in shadow-canary-templates@0.5.0 yet.

Upstream manifest note: shadow-canary-templates@0.5.0 still ships a
manifest.json that reports version 0.2.1 and omits 3 files from the copy
list (bucket-info, rollback-shadow, shadow-history). Copied those manually
from the package's files/ directory. Same workaround as the 0.4.0 bump.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@gtko
gtko merged commit 7d86db1 into production Apr 24, 2026
2 checks passed
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