Skip to content

ci(release): remove the tag-push release workflow - #696

Merged
aliasunder merged 8 commits into
ci/cli-release-notes-filterfrom
ci/remove-tag-push-release
Oct 22, 2026
Merged

aliasunder merged 8 commits into
ci/cli-release-notes-filterfrom
ci/remove-tag-push-release

Conversation

@aliasunder

Copy link
Copy Markdown
Owner

Summary

Server releases go through the Manual Release workflow only, so this removes the unused tag-push release workflow and updates the docs to describe one release path. Removing it also frees a slot in the deploy-prod concurrency group: the tag that Manual Release pushes as the release App still started auto_release.yml, whose jobs all skipped but whose run waited in the group and took its one queued slot (for v0.55.0 that run was cancelled two seconds after a CLI release was dispatched).

  • .github/workflows/auto_release.yml: deleted.
  • DEPLOY.md: CI/CD intro, workflow table (row removed; the manual_release.yml and dockerhub-description.yml rows describe the one release workflow), the "Why two release paths?" note removed, the MCP Registry note, and "Cutting a release" reduced to the Manual Release steps.
  • CONTRIBUTING.md: Release Process describes Manual Release only; the branch-ruleset sentence no longer mentions a tag push's version-bump PR.
  • SECURITY.md: the cosign verify-blob identity regexp accepts manual_release.yml only.
  • .github/workflows/publish-registry.yml: the checkout comment names the one workflow that pushes the release tag.

Signing identity

Every published v* release that has a digests.txt.sigstore.json was signed by manual_release.yml. I downloaded the bundle for every server release and read the certificate's subject alternative name:

  • v0.38.0 through v0.55.0 (47 releases): https://github.com/aliasunder/vault-cortex/.github/workflows/manual_release.yml@refs/heads/main.
  • v0.37.4 and earlier: no bundle (signing started after v0.37.4).

No release was signed by auto_release.yml, so the narrowed regexp still verifies every signed release.

Test plan

  • actionlint .github/workflows/publish-registry.yml: no findings. A full actionlint run reports only the two existing shellcheck notes in cli_release.yml.
  • npx markdownlint-cli2 DEPLOY.md CONTRIBUTING.md SECURITY.md: 0 issues.
  • npx prettier --check on the changed files: all formatted.
  • npm test: 5749 passed, 1 failed. The failure is scripts/__tests__/lint-shell.test.ts ("checks every shell script in the repo when given no paths"): its expected list lacks .github/scripts/generate-cli-notes.sh, which the base branch adds. This PR does not touch that script or the test.
  • Searched the repo (excluding CHANGELOG.md) for auto_release, "Auto Release" and "tag push": no references to the removed workflow remain. The two "tag push" hits left, in manual_release.yml and cli_release.yml, describe each workflow's own atomic push.

🤖 Generated with Claude Code

Server releases go through the Manual Release workflow only. The
tag-push workflow was an unused second path, and the tag that Manual
Release pushes still started it: its jobs skipped, but the run waited
in the deploy-prod concurrency group and took the group's one queued
slot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@aliasunder
aliasunder added this pull request to stack #695 October 21, 2026 23:41
@umm-actually

umm-actually Bot commented Oct 21, 2026

Copy link
Copy Markdown

Drop the dead 'push a new tag' release path from the token rotation steps
Medium severity · correctness · high confidence

DEPLOY.md:445 — beyond the diff's line ranges, in code the changes touch or depend on.

The Rotating MCP_AUTH_TOKEN section still offers pushing a new tag as an alternative to dispatching Manual Release, but this PR deletes the only workflow that fired on v* tag pushes. Following that alternative now triggers nothing: no deploy runs, the instance keeps the old token, and the rotation silently doesn't happen.

Failure scenario: The maintainer rotates MCP_AUTH_TOKEN following this section and picks the tag branch: git tag v0.55.1 && git push origin v0.55.1. With auto_release.yml deleted, no workflow triggers — the instance .env still holds the old token, so the rotation is silently skipped and clients keep authenticating with the old secret until an actual release dispatch runs.

Suggested fix
Reduce the comment to the surviving path: `# Then dispatch manual_release.yml — CI takes care of the rest.`

umm-actually · z-ai/glm-5.3-flash

@umm-actually

umm-actually Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

umm-actually re-reviewed at a72c5ab

1 new finding(s) posted (6 tracked finding(s) across all runs).

Context notes
  • Priority docs already in context: SECURITY.md

umm-actually · z-ai/glm-5.3-flash

aliasunder and others added 2 commits October 21, 2026 20:04
With the tag-push release workflow removed, only release and deploy dispatches join the deploy-prod group.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@umm-actually

umm-actually Bot commented Oct 22, 2026

Copy link
Copy Markdown

Update GOVERNANCE.md's 'built from tagged commits' release claim
Low severity · correctness · medium confidence

GOVERNANCE.md:33 — beyond the diff's line ranges, in code the changes touch or depend on.

The Continuity section states releases are built by GitHub Actions from tagged commits, but with auto_release.yml deleted in this PR, a v* tag push no longer builds or deploys anything — releases are produced only by dispatching the Manual Release workflow. A successor or fork reading this would conclude pushing a tag cuts a release, which now silently does nothing.

Failure scenario: A maintainer successor (the reader this section targets) cuts a release by pushing a v* tag per this sentence; nothing triggers, no image is published, and the release silently doesn't happen.

Suggested fix
Rewrite the sentence to name the Manual Release workflow dispatch as the release path, e.g. 'Releases are built by GitHub Actions via the Manual Release workflow dispatch — there are no maintainer-local build steps.'

umm-actually · z-ai/glm-5.3-flash

@umm-actually

umm-actually Bot commented Oct 22, 2026

Copy link
Copy Markdown

Scope the signed-digest guarantee to releases since v0.38.0
Low severity · conventions · high confidence

SECURITY.md:325 — beyond the diff's line ranges, in code the changes touch or depend on.

Pre-existing: The Release Signing intro states every v* release includes a signed digest file, but this PR's own verification establishes that releases through v0.37.4 have no bundle (signing started at v0.38.0). While this PR narrows the verify regexp in this same section, the headline guarantee above it remains overstated, so a reader verifying an older release per this section finds nothing to download or check.

Failure scenario: A deployer or auditor picks an older release (e.g. v0.37.4) and follows SECURITY.md's verification instructions: gh release download v0.37.4 --pattern 'digests.txt*' finds no matching asset and the promised 'every release' signature cannot be checked, even though the doc guarantees it exists.

Suggested fix
Rewrite the sentence to state the actual contract, e.g. "Releases since v0.38.0 include a signed digest file; earlier releases predate signing and carry no bundle."

umm-actually · z-ai/glm-5.3-flash

DEPLOY.md's MCP_AUTH_TOKEN rotation steps still offered pushing a new tag, which no longer starts a release.

Ship-Check: pr-review · claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@umm-actually

umm-actually Bot commented Oct 22, 2026

Copy link
Copy Markdown

Register generate-cli-notes.sh in ShellCheck's glob list
Medium severity · conventions · medium confidence

.github/workflows/cli_release.yml:239 — beyond the diff's line ranges, in code the changes touch or depend on.

Pre-existing: the base branch adds .github/scripts/generate-cli-notes.sh but never registers it in scripts/lint-shell.ts's SHELL_SCRIPT_GLOBS, violating AGENTS.md's rule that a new shell script's path is added there. npm run lint:shell therefore never checks the release-notes script, and the coverage test fails on this PR's merge ref, so the required checks job cannot go green until the registration lands.

Failure scenario: This PR's merge ref contains the base branch's new script, so npm test fails scripts/tests/lint-shell.test.ts ('checks every shell script in the repo when given no paths'), the required checks job reports red, and the main ruleset blocks the merge; meanwhile dispatching Release CLI ships a notes script whose shell code ShellCheck has never checked, so its bugs surface only at release time.

Suggested fix
Add `.github/scripts/generate-cli-notes.sh` to `SHELL_SCRIPT_GLOBS` in `scripts/lint-shell.ts` and to the expected list in `scripts/__tests__/lint-shell.test.ts` — in this PR or in the base branch's ci/cli-release-notes-filter PR, whichever merges first.

umm-actually · z-ai/glm-5.3-flash

aliasunder and others added 3 commits October 21, 2026 20:19
- DEPLOY.md: the manual_release.yml row lists every called workflow and the
  signed digests; the MCP Registry note names the hardcoded server name a
  fork must rename and says a failed publish does not stop the Release;
  Cutting a release names the bumped files, skip_deploy, and which
  workflows push to main
- CONTRIBUTING.md: the release-notes file exclusions become a list
- SECURITY.md: the digest comparison names the tag for each target
- Workflow comments name the workflows sharing the deploy-prod group, the
  re-dispatch remedy, and the caller job behind the registry tag

Ship-Check: code-quality · claude-opus-5-5

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ks change

The workflows table now says the release job runs beside the registry and
Docker Hub jobs after deploy, matching the needs graph and the fork note's
"a failed publish does not stop the GitHub Release". The notes come from
generate-notes.sh, not GitHub's auto-generated notes. The fork note names
the hardcoded ghcr.io/aliasunder/vault-cortex path, and "Cutting a release"
says workflow, since several jobs do the work.

Ship-Check: bug-check · claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With tag pushes no longer starting a release, "built from tagged commits" could read as a release path. The Continuity list now names Manual Release and Release CLI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@aliasunder

Copy link
Copy Markdown
Owner Author

Responses to the PR-level findings:

  • #issuecomment-6329061774 (token rotation still offers "push a new tag"): fixed in 25c2ecc; the step now says to dispatch manual_release.yml.
  • #issuecomment-6329374366 (GOVERNANCE.md "built from tagged commits"): the sentence was accurate, since the deploy job builds from the release tag, but with tag pushes no longer starting anything it could read as a release path. It now names the workflows that cut releases: Manual Release for the server and Release CLI for the npm package.
  • #issuecomment-6329374578 (scope the signed-digest guarantee to releases since v0.38.0): the maintainer decided not to add release-history detail to SECURITY.md before 1.0.
  • #issuecomment-6329438717 (register generate-cli-notes.sh in ShellCheck's globs): already covered. SHELL_SCRIPT_GLOBS in scripts/lint-shell.ts includes .github/scripts/*.sh, which matches the script, and the base branch lists it in scripts/__tests__/lint-shell.test.ts's expected scripts (7e18567), where that test passes.

🔍 ship-check · pr-monitor · claude-opus-5-5

@umm-actually

umm-actually Bot commented Oct 22, 2026

Copy link
Copy Markdown

Pin the prettier version the release bump step runs
Low severity · ci · medium confidence

.github/workflows/manual_release.yml:126 — beyond the diff's line ranges, in code the changes touch or depend on.

Pre-existing: the bump step runs npx prettier --write server.json with no dependency install anywhere in this job, so npx downloads whatever prettier version npm serves that day instead of the repo's pinned one. Unpinned code executes in the job holding the release App's private key, and a formatting change between prettier versions would land a server.json on main that fails the pinned-version prettier:check in the required checks job.

Failure scenario: A prettier release changes JSON formatting (or the registry-served package is tampered with): the release run's npx fetches it unpinned, the version-bump commit lands on main with server.json formatted differently than the pinned version produces, and the checks job's prettier:check fails on main, blocking every open PR until the file is re-formatted — or the downloaded prettier executes with RELEASE_APP_PRIVATE_KEY available in the job's env context.

Suggested fix
Add an `npm ci` step before the bump step so `npx prettier` resolves the repo's locked devDependency, exactly as cli_release.yml already does before its own `npx prettier --write cli/package.json` step.

umm-actually · z-ai/glm-5.3-flash

@umm-actually

umm-actually Bot commented Oct 22, 2026

Copy link
Copy Markdown

Verify the mcp-publisher tarball against a pinned checksum
Medium severity · security · high confidence

.github/workflows/publish-registry.yml:44 — beyond the diff's line ranges, in code the changes touch or depend on.

Pre-existing: the Install step pipes the mcp-publisher tarball from a mutable GitHub release tag into execution without any checksum or digest verification, in the one job holding id-token: write. A re-uploaded asset or moved v1.7.9 tag executes attacker code that receives the repo's registry OIDC identity. The repo's own posture treats release assets as mutable — the Dockerfile digest-pins the s6 tarballs for exactly this reason, and the gitleaks workflow verifies its download's checksum.

Failure scenario: The modelcontextprotocol/registry v1.7.9 release asset is replaced or its tag re-pointed (release assets on GitHub are mutable, per the repo's own Dockerfile rationale): the next Manual Release's publish job downloads and executes the trojaned binary with id-token: write; it receives the repo's registry OIDC identity and can publish an attacker-controlled server.json entry to the official MCP Registry under io.github.aliasunder/vault-cortex.

Suggested fix
Pin the tarball's sha256 alongside MCP_PUBLISHER_VERSION and verify before extracting, mirroring the Dockerfile's s6 digest pins:

yaml
      - name: Install mcp-publisher (pinned)
        env:
          # Bump together with MCP_PUBLISHER_VERSION; take the value from the release's .sha256 asset at bump time.
          MCP_PUBLISHER_TARBALL_SHA256: "<sha256 of v1.7.9 mcp-publisher_linux_amd64.tar.gz>"
        run: |
          curl -sSLo /tmp/mcp-publisher.tar.gz \
            "https://github.com/modelcontextprotocol/registry/releases/download/v${MCP_PUBLISHER_VERSION}/mcp-publisher_linux_amd64.tar.gz"
          echo "${MCP_PUBLISHER_TARBALL_SHA256}  /tmp/mcp-publisher.tar.gz" | sha256sum -c
          tar xzf /tmp/mcp-publisher.tar.gz mcp-publisher

umm-actually · z-ai/glm-5.3-flash

@aliasunder

Copy link
Copy Markdown
Owner Author

Responses to the PR-level findings:

  • #issuecomment-6329726368 (pin the prettier version the release bump step runs): valid. The maintainer approved fixing it in a follow-up, together with the App token that .git/config keeps during that step.
  • #issuecomment-6330401811 (verify the mcp-publisher tarball against a pinned checksum): valid. The maintainer approved fixing it in the same follow-up: pin the tarball's SHA-256 beside MCP_PUBLISHER_VERSION and check it before extracting. Upstream publishes a checksums file for each release.

🔍 ship-check · pr-monitor · claude-opus-5-5

@aliasunder
aliasunder merged commit 49e8528 into main Oct 22, 2026
18 checks passed
@aliasunder
aliasunder deleted the ci/remove-tag-push-release branch October 22, 2026 02:09
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