fix(release): lockstep all 9 version surfaces + enforce in CI#35
Merged
Conversation
The version-lockstep gate ran ONLY in the manual scripts/e2e-smoke.sh --
never check-all.sh or publish.yml -- and checked only 3 JSON surfaces
(installer / mcp-server / codex plugin.json). So five RELEASE-facing
manifests silently drifted while the code shipped 1.6.4:
- gemini/extensions/ijfw/gemini-extension.json 1.5.6 (Sean-confirmed lockstep)
- claude/.claude-plugin/marketplace.json 1.5.6 (marketplace listing)
- codex/.agents/plugins/marketplace.json 1.5.6 (marketplace listing;
its plugin_manifest already pointed at plugin.json@1.6.4 -- internally
inconsistent, proving a missed bump not an independent cadence)
- hermes/plugins/ijfw/plugin.yaml 1.5.1 (SHIPS verbatim to
~/.hermes/plugins/ijfw via the installer -- a 1.6.4 user got a 1.5.1 manifest)
- wayland/plugins/ijfw/plugin.yaml 1.5.1 (in-repo source manifest;
Wayland's SHIPPED toml is rendered from installer/package.json, so this one
is source-only, but kept in lockstep for coherence)
Fix:
- bump all five to 1.6.4;
- rewrite check-version-lockstep.sh from 3 JSON surfaces to all 9 release
surfaces (7 JSON incl. claude plugin.json + both marketplaces + gemini, plus
2 YAML via a zero-dep version-line reader). Root package.json stays EXCLUDED
-- private ijfw-workspace stub at 1.0.0, not a release surface. Manifest path
passed via argv (not string-interpolated) so a checkout path with a quote
can't break require();
- WIRE check-version-lockstep.sh into check-all.sh (fail-fast, before the
~5min suite) so CI (ci.yml + publish.yml) enforces lockstep every run;
- update e2e-smoke.sh's stale "installer/mcp-server/codex" message.
Verified: script passes (all 9 at 1.6.4), shellcheck clean, per-surface
negative control catches drift on EACH of the 9 independently; full
check-all.sh green (suite 3614/0) + preflight 11/11.
Adversarial review round 1 REJECTED the initial 7-surface version: it found
hermes+wayland plugin.yaml at 1.5.1 that a JSON-only gate could never catch
(Hermes ships its manifest verbatim). This round adds YAML coverage + the
two bumps. Scope note for review: Overwatch confirmed the GEMINI surface
locksteps; I included the other four drifted surfaces (same class) so the
gate is not hollow. Narrow if any has an independent cadence.
FerroxLabs
added a commit
that referenced
this pull request
Jul 11, 2026
…ix (#36) Supply-chain hardening for the publish pipeline (v1.6.4 cross-audit dimension d + Overwatch card). Token blast-radius is already closed (Sean made NPM_TOKEN granular, 2-package scope); this PR is the WHO-can-trigger + what-can-ship half. WORKFLOW-only + a runbook note -- no live admin edits. publish.yml: - gate the publish job on the protected `release` environment (required reviewer): a v* tag, regardless of who pushes it, now pauses for human approval before any npm publish runs. Overwatch/Sean configure the env protection + the tag-creation ruleset (only the release actor may create v*) outside the workflow. - assert the pushed tag matches installer/package.json AND mcp-server/ package.json version before publishing. Without it, `git tag v9.9.9` on a 1.6.5 commit would publish 1.6.5 under a v9.9.9 Release. check-all's 9-surface version-lockstep gate (rebased in from #35) proves all in-repo surfaces agree, so tag == installer+mcp + lockstep == tag == every published + manifest version. - fix the dist-tag rule: the old check matched ONLY `-rc.`, so a `-beta`/`-alpha` tag silently shipped to `latest`. Now a strict anchored regex validates the tag shape FIRST (adversarial review: the old `case` globs would have let `v1.2.3.4`/`v1.2.3extra` fall through to `latest`), then stable -> latest, ANY prerelease -> next, malformed -> refused. - injection-safe: tag values flow via env (TAG_REF), never inlined into run: scripts (verified an injected `; rm -rf` tag is neutralized). docs/CI-PUBLISH.md: 'current pipeline' callout overriding the stale legacy 'no NPM_TOKEN / nothing to rotate' line -- documents the granular token + its ~2026-10-08 (90-day) ROTATION deadline, the release-env gate, the tag<->version assert, and the dist-tag rule. Plus a settings-audit block (gh api one-liners) so an operator can VERIFY the release-env required- reviewer + tag-creation ruleset are actually applied -- the workflow can't enforce them and an unconfigured environment auto-creates UNPROTECTED. Verified: publish.yml valid YAML, environment key present on publish job, banned-char clean; dist-tag + assert logic unit-tested across stable/rc/ beta/alpha/malformed/injection tags + matching/mismatching versions. Out of scope (per Overwatch): token/OIDC migration (granular suffices), account classic-token cleanup (Sean owns), the tag-creation ruleset + release-env protection SETTINGS (admin, not workflow). Overwatch reviews this as release-infra. Co-authored-by: ci <sean@seandonahoe.com>
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Lockstep all 9 release-versioned surfaces to 1.6.4 and enforce it in CI (wired check-version-lockstep.sh into check-all.sh). Fixes the silent drift: gemini + both marketplaces were at 1.5.6, hermes + wayland plugin.yaml at 1.5.1. Two adversarial review rounds (round 1 REJECT caught the hermes/wayland YAML surfaces a JSON-only gate could never see; round 2 APPROVE). Suite 3614/0 Node 22, preflight 11/11, per-surface negative control green on all 9. Overwatch: Sean confirmed gemini locksteps; I included the 4 other same-class drifted surfaces — narrow if any has independent cadence.