Skip to content

ci: pin Thailand deploy to immutable sha- tag, never a moving tag#38

Merged
sangwa merged 2 commits into
mainfrom
ci/deploy-pin-immutable-sha
Jun 19, 2026
Merged

ci: pin Thailand deploy to immutable sha- tag, never a moving tag#38
sangwa merged 2 commits into
mainfrom
ci/deploy-pin-immutable-sha

Conversation

@sangwa

@sangwa sangwa commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Problem

Deploying the main (or a feature-branch) Thai image via workflow_dispatch with an empty image_tag resolved to the moving latest/<slug> tag and wrote that into the gitops values.yaml:

axion.sandbox.image:
  tag: "latest"          # <-- mutable tag in a pinned manifest = smell
  digest: "sha256:..."

Even though the digest actually pins the image, a latest (or branch-slug) tag: reads as floating and isn't traceable to a specific build.

Fix

For an empty-input dispatch, resolve the moving tag to its digest and then de-reference it to the immutable sha-<short> tag that carries the same digest, and pin that:

  • Fast path — try sha-${GITHUB_SHA::7} (the dispatched commit is usually the build commit); use it if its digest matches.
  • Fallback — scan sha- tags for the matching digest (covers the case where HEAD built no image, so latest points further back).
  • Refuses to pin if no sha- tag matches the digest (never writes a mutable tag).

Semver deploys are unchanged: workflow_run (released version) and an explicit image_tag input are already immutable and pinned as-is.

Validation

Exercised the resolve logic against a mocked registry — all pass:

Case Result
dispatch main, fast path (sha-HEAD == latest) pins sha-<HEAD>
dispatch main, HEAD built no image fallback finds matching sha-
dispatch main, no sha- matches errors (refuses mutable)
dispatch feature branch slug pins sha-<HEAD>
explicit input 0.3.0 pinned as-is
workflow_run semver pinned as-is
explicit input not published errors

actionlint clean; YAML valid; CLAUDE.md updated.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores

    • Improved the Thailand deployment GitOps workflow to resolve requested image tags to their matching image digests and ensure manifests are pinned to immutable sha-* references (instead of mutable tags), failing when a matching immutable tag can’t be found.
  • Documentation

    • Clarified the workflow’s image_tag input behavior (including the “empty input” case) to explain how moving tags are de-referenced to immutable sha-* pins at the same digest and when errors occur.

Deploying the "main" (or a feature branch) image via workflow_dispatch resolved
to the moving `latest`/`<slug>` tag and wrote that into the gitops values.yaml.
A mutable tag in a K8s manifest is a smell: it reads as floating even though the
digest pins it, and it isn't traceable to a specific build.

Resolve the moving tag to a digest, then de-reference it to the immutable
sha-<short> tag at the same digest and pin that. Fast path tries
sha-${GITHUB_SHA::7} (the dispatched commit is usually the build commit);
fallback scans sha- tags for the matching digest (e.g. when HEAD built no image
and latest points further back). Refuses to pin if no sha- tag matches.

Semver deploys (workflow_run, or an explicit image_tag input) are unchanged —
already immutable, pinned as-is.

Verified the resolve logic against a mocked registry across fast-path,
fallback, no-match, slug, explicit-input and workflow_run cases.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 19, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 422a3fab-b689-45ab-9898-12dd29e9900a

📥 Commits

Reviewing files that changed from the base of the PR and between 5b14ec5 and 8902b03.

📒 Files selected for processing (1)
  • .github/workflows/deploy-thailand.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/deploy-thailand.yml

Walkthrough

The Thailand deploy workflow (deploy-thailand.yml) is updated to enforce immutable image tag pinning in the GitOps values file. The workflow_dispatch input description and inline documentation are updated to reflect that an empty image_tag input will target the branch's moving tag but de-reference it to an immutable sha-<short> tag at the same digest. In the Resolve target image step, helper functions (repo, slugify, digest_of) are defined earlier, and a moving flag is introduced to distinguish between mutable tags (latest, branch slug) and immutable ones. When moving=true, the workflow resolves the digest of the moving tag via registry lookup, attempts a fast-path match against the current sha-<short>, then scans all existing sha-* tags via oras repo tags for a digest match, failing if none is found. CLAUDE.md is updated to document this de-referencing behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • EternisAI/agent-sandbox#35: Introduced the Thailand GitOps deploy workflow that resolves an image tag to a GHCR digest and pins the tag/digest into the GitOps values.yaml, which this PR directly extends with immutable sha-tag de-referencing logic.

Poem

🐇 A moving tag drifts like a cloud in the sky,
So I chase down the sha- before letting it fly.
I scan through the registry, digest by digest,
Until the immutable match passes the test.
No mutable refs in our manifests, hooray—
The bunny pins sha- and hops on its way! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and concisely summarizes the main change: pinning Thailand deployments to immutable sha- tags instead of moving tags, which is the core objective.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/deploy-pin-immutable-sha

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/deploy-thailand.yml:
- Around line 120-125: The condition checking INPUT_TAG on line 120 accepts any
non-empty value without validating whether it's immutable, allowing mutable tags
like latest to be pinned as the tag value. Add validation logic after the `if [
-n "${INPUT_TAG}" ]` check to enforce an allowlist of immutable tag patterns
(such as sha-* or semantic versioning formats) before accepting the INPUT_TAG as
the pinned tag. Reject any INPUT_TAG that doesn't match the immutable pattern
allowlist to prevent mutable tags from being used as pinned deployment tags.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cbada39b-9024-4a93-937f-11b79837d19c

📥 Commits

Reviewing files that changed from the base of the PR and between 63a37c6 and 5b14ec5.

📒 Files selected for processing (2)
  • .github/workflows/deploy-thailand.yml
  • CLAUDE.md

Comment thread .github/workflows/deploy-thailand.yml
The explicit workflow_dispatch image_tag was pinned verbatim, so image_tag=latest
(or a branch slug) would write a mutable tag into the manifest — the very smell
this workflow removes for the empty-input path.

Validate explicit input against an immutable allowlist (sha-<commit> or X.Y.Z)
and reject anything else, pointing the user to leave image_tag empty for a
branch deploy (which de-references to the sha- tag). Empty-input and
workflow_run paths are unchanged.

Verified the allowlist rejects latest / slugs / v-prefixed / malformed and
accepts sha-<hex> and X.Y.Z, and that valid immutable inputs still pin as-is.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@sangwa sangwa merged commit 11c2b67 into main Jun 19, 2026
3 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