Skip to content

fix(preview): bound CMS preview-alias slug to a valid DNS label - #1665

Merged
Adam-S-Daniel merged 1 commit into
mainfrom
claude/non-required-check-red-oExrt
May 24, 2026
Merged

fix(preview): bound CMS preview-alias slug to a valid DNS label#1665
Adam-S-Daniel merged 1 commit into
mainfrom
claude/non-required-check-red-oExrt

Conversation

@Adam-S-Daniel

Copy link
Copy Markdown
Owner

Why

The deploy-preview job's per-CMS-slug alias step builds preview-cms-<slug>.adamdaniel.ai directly from the branch ref with no length cap. For a long entry title the host's first DNS label exceeds the 63-octet limit (RFC 1035), so the GitHub Deployments registration that embeds that URL is rejected and the whole job goes red — even though the preview-pr<N> preview deployed fine and is live. Because that step fails before the "Post preview URL comment" step, the PR also gets no preview bot comment at all.

This is exactly what's happening on #941 (branch cms/posts/2026-05-17-safely-keep-your-agent-iterating-autonomously-with-gitleaks-and-pr-comments): the slug is 92 chars → a 104-char host label. deploy-preview is a non-required check, so the PR stays mergeable but shows red.

What changed

  • scripts/cms-preview-slug.sh (new) — single source of truth for the slug. Strips cms/, flattens /-, then bounds the result so preview-cms-<slug> stays ≤ 63 chars (slug ≤ 51). Short slugs pass through unchanged; over-long ones keep a 42-char readable prefix and append an 8-hex content hash — deterministic (same entry → same host across Decap close/reopen draft cycles) and collision-resistant (two long titles sharing a 42-char prefix still differ).
  • .github/workflows/deploy-preview.yml — both the deploy-preview and teardown-preview cms_slug steps now call the shared script, so they can't drift on which cms-<slug>/ prefix to publish vs. clean up. Teardown gains a Checkout (it had none) pinned to the PR head SHA, so it computes the identical prefix at PR-close.
  • e2e/deploy-preview-cms-slug.test.js — the "same sed expression ×2" invariant becomes "both jobs call the shared script ×2" + "both jobs check out the repo"; the JS slug re-implementation is replaced with tests that exec the real script (boundary at 51/52, the Create Post “2026-05-17-safely-keep-your-agent-iterating-autonomously-with-gitleaks-and-pr-comments” #941 branch → valid ≤63 host, determinism, collision-resistance).
  • e2e/select-specs.js — maps the test to re-run when the script or deploy-preview.yml changes.

No infrastructure change: the CloudFront preview-router (infrastructure/bootstrap/template.yaml) already maps the host to the S3 prefix by pure string match ^preview-cms-([a-z0-9-]+)\.adamdaniel\.ai$, and the wildcard cert/Route53 cover any valid label.

For #941 the host becomes preview-cms-posts-2026-05-17-safely-keep-your-agent-it-b8a6cdab.adamdaniel.ai (exactly 63 chars) — and now resolves and serves instead of failing the job.

Test plan

  • Ran the real script across all cases (non-cms→empty, short unchanged, 51/52 boundary, Create Post “2026-05-17-safely-keep-your-agent-iterating-autonomously-with-gitleaks-and-pr-comments” #941 → 51-char slug / 63-char host, deterministic, collision-resistant) — all pass.
  • Validated every structural grep and slug assertion in deploy-preview-cms-slug.test.js directly against the real files (Playwright isn't installed in the dev container; the e2e/select lanes will run the spec in CI — the new select-specs.js rule selects it).
  • deploy-preview.yml parses as valid YAML; teardown step order intact.
  • Confirmed sibling deploy-preview tests (deploy-commit-metadata, preview-bot-comment) and the selector's own test are unaffected.
  • CI scan (gitleaks) — runs on the PR (the local pre-commit gitleaks binary isn't present in the cloud container; commit used the hook's documented SKIP_SECRETS_SCAN=1, diff contains no secrets).

Generated by Claude Code

The deploy-preview job's per-CMS-slug alias derived
`preview-cms-<slug>.adamdaniel.ai` straight from the branch ref with no
length cap. For a long entry title the first DNS label exceeds the
63-octet limit, so the GitHub Deployments registration that embeds it is
rejected and the whole job goes red — even though the pr-<N> preview
deployed fine. That failure also skipped the preview bot comment, so the
PR got no preview link at all.

Extract the slug derivation into scripts/cms-preview-slug.sh, shared by
the deploy and teardown jobs so they always agree on the `cms-<slug>/`
prefix. When `preview-cms-<slug>` would exceed 63 chars the script keeps
a 42-char readable prefix and appends an 8-hex content hash:
deterministic, stable across Decap draft cycles, and collision-resistant.
The CloudFront router is already a pure host->prefix string map, so no
infrastructure change is needed. Teardown gains a Checkout (it had none)
so the script is on disk to compute the identical prefix at PR-close.

https://claude.ai/code/session_01R3Lw9zY6qKTBJ3nXpyWAvD
@github-actions github-actions Bot added the cms/draft Content draft — not ready for publish label May 24, 2026
@github-actions

github-actions Bot commented May 24, 2026

Copy link
Copy Markdown
Contributor

🗑️ Preview environment cleaned up.

@Adam-S-Daniel
Adam-S-Daniel merged commit e0d0256 into main May 24, 2026
21 checks passed
@Adam-S-Daniel
Adam-S-Daniel deleted the claude/non-required-check-red-oExrt branch May 24, 2026 20:29
Adam-S-Daniel added a commit that referenced this pull request May 24, 2026
…nup (#1667)

cms-publish-flow.spec.js creates a smoke post via the local Decap backend
and runs `jekyll build` into the SHARED _site/ the Playwright webServer
serves, which bakes /blog/e2e-publish-flow-smoke/ (and the manufactured
/tags/e2e-smoke-flow-tag/ archive) into _site/sitemap.xml. Its cleanup
deleted the rendered dirs but NOT those sitemap entries, leaving them
advertised-but-404ing. image-alt-text.spec.js runs in the same e2e-admin
job, shares that _site/, walks the sitemap, and failed:
"expected 200 from /blog/e2e-publish-flow-smoke/, got 404" — an
intermittent, order-dependent failure on unrelated PRs (e.g. #1654).

Fix: extend removeSmokePost() to prune the orphaned <url> blocks from
_site/sitemap.xml so it stays consistent with what's on disk. Extracted
the prune into a pure helper (e2e/sitemap-prune.js) with a unit test
(e2e/sitemap-prune.test.js); verified against the real built sitemap.

Not related to #1665 (e0d0256), which only touches cms/* preview-alias
DNS slugs in deploy-preview.yml.

https://claude.ai/code/session_01Bj5DjryAqCqW4czqyZ47f8

Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added the not-decap-created PR was not created by Decap CMS (head branch is not cms/<col>/<slug>) label May 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cms/draft Content draft — not ready for publish not-decap-created PR was not created by Decap CMS (head branch is not cms/<col>/<slug>)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants