Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"plugins": [
{
"name": "genie",
"version": "5.260725.5",
"version": "5.260725.8",
"source": "./plugins/genie",
"description": "Human-AI partnership for Claude Code. Share a terminal, orchestrate workers, evolve together. Brainstorm ideas, wish them into plans, make with parallel agents, ship as one team. A coding genie that grows with your project."
}
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/release-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,6 @@ jobs:
VERSION: ${{ inputs.version }}
CHANNEL: ${{ inputs.channel }}
SOURCE_SHA: ${{ inputs.source_sha }}
TRIGGER_SHA: ${{ inputs.trigger_sha }}
SOURCE_BRANCH: ${{ inputs.source_branch }}
SOURCE_CI_RUN_ID: ${{ inputs.source_ci_run_id }}
CONTROL_SHA: ${{ github.sha }}
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/sign-attest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,6 @@ jobs:
SOURCE_SHA: ${{ inputs.source_sha }}
SOURCE_BRANCH: ${{ inputs.source_branch }}
SOURCE_CI_RUN_ID: ${{ inputs.source_ci_run_id }}
TRIGGER_SHA: ${{ inputs.trigger_sha }}
CONTROL_SHA: ${{ github.sha }}
RUN_ID: ${{ github.run_id }}
RUN_ATTEMPT: ${{ github.run_attempt }}
Expand Down Expand Up @@ -380,6 +379,10 @@ jobs:
SOURCE_SHA: ${{ inputs.source_sha }}
SOURCE_BRANCH: ${{ inputs.source_branch }}
SOURCE_CI_RUN_ID: ${{ inputs.source_ci_run_id }}
# Required by release-generic-provenance.sh verify-exact on the
# automated channels: it binds the provenance's triggering
# workflow_run head to this value and exits 2 when it is absent.
TRIGGER_SHA: ${{ inputs.trigger_sha }}
CONTROL_SHA: ${{ github.sha }}
run: |
set -euo pipefail
Expand Down
19 changes: 16 additions & 3 deletions .github/workflows/version.yml
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,14 @@ jobs:
run: |
PREFIX="${{ steps.context.outputs.prefix }}"
TODAY=$(date -u +%y%m%d)
EXISTING=$(git tag --list "v${PREFIX}.${TODAY}.*" | wc -l)
BUILD_NUMBER=$((EXISTING + 1))
# Highest existing build number + 1, never the count: a gap (a tag
# deleted, or a build number burned by a failed release) would make
# count+1 collide with an existing tag, and the push failure below is
# reported as a benign race, silently dropping the release.
HIGHEST=$(git tag --list "v${PREFIX}.${TODAY}.*" \
| sed -n "s|^v${PREFIX}\.${TODAY}\.\([0-9][0-9]*\)$|\1|p" \
| sort -n | tail -1)
BUILD_NUMBER=$(( ${HIGHEST:-0} + 1 ))
Comment thread
namastex888 marked this conversation as resolved.
Resolved
VERSION="${PREFIX}.${TODAY}.${BUILD_NUMBER}"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "build_number=${BUILD_NUMBER}" >> "$GITHUB_OUTPUT"
Expand Down Expand Up @@ -313,7 +319,14 @@ jobs:
# in CI logs and detector-greppable. The next merge's run catches
# up.
SHORT_SHA="${TRIGGER_SHA:0:7}"
if ! git push --atomic origin "HEAD:refs/heads/dev" "refs/tags/v${VERSION}"; then
if ! push_output=$(git push --atomic origin "HEAD:refs/heads/dev" "refs/tags/v${VERSION}" 2>&1); then
printf '%s\n' "$push_output" >&2
# A tag collision is a version-derivation defect, not a race: exiting
# 0 here would drop the release with a green run and no diagnosis.
if printf '%s' "$push_output" | grep -qiE 'already exists|cannot lock ref|tag .* exists'; then
echo "::error ::release-version.tag-collision v${VERSION} already exists; version derivation picked a used build number"
exit 1
fi
Comment thread
namastex888 marked this conversation as resolved.
Resolved
echo "::notice ::release-race.next-tag-pin-skipped.detected dev advanced past triggering SHA ${SHORT_SHA}; tag push skipped — next merge will republish"
exit 0
fi
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@automagik/genie",

"version": "5.260725.5",
"version": "5.260725.8",
"description": "Collaborative terminal toolkit for human + AI workflows. NOTE: npm distribution discontinued 2026-05-09 — install via `curl -fsSL https://raw.githubusercontent.com/automagik-dev/genie/main/install.sh | bash` (cosign + SLSA verified). See https://automagik.dev/genie/release-process",

"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion plugins/genie/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "genie",
"version": "5.260725.5",
"version": "5.260725.8",
"description": "Human-AI partnership for Claude Code. Share a terminal, orchestrate workers, evolve together. Brainstorm ideas, turn them into wishes, execute with /work, validate with /review, and ship as one team.",
"author": {
"name": "Namastex Labs"
Expand Down
2 changes: 1 addition & 1 deletion plugins/genie/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "genie",
"version": "5.260725.5",
"version": "5.260725.8",
"description": "Plan, execute, review, and ship software with Genie workflows in Codex.",
"author": {
"name": "Namastex Labs",
Expand Down
2 changes: 1 addition & 1 deletion plugins/genie/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "genie-plugin",
"version": "5.260725.5",
"version": "5.260725.8",
"private": true,
"description": "Runtime dependencies for genie bundled CLIs",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion plugins/hermes-genie/plugin.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: genie
version: 5.260725.5
version: 5.260725.8
description: "Native Hermes surface for Genie orchestration: read-only status plus work-plan and review-plan gap tools that the MCP board surface does not cover, hooks, commands, and a thin cockpit skill. Board/task truth comes from the genie MCP tools."
provides_tools:
# Default surface: exactly the three gap tools the MCP board surface does not cover.
Expand Down
57 changes: 57 additions & 0 deletions scripts/release-docs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,63 @@ describe('Group E release and documentation contracts', () => {
expect(read('src/genie.ts')).toContain(".command('__install-promote', { hidden: true })");
});

test('the admitting CI head is plumbed to provenance verification end to end', () => {
// The generic SLSA provenance embeds the workflow_run that TRIGGERED the
// release, whose head is the commit CI ran on — one BEFORE the
// [auto-version] bump the tarballs are built from. Verification must bind
// that field to the trigger commit, never to source_sha (they can never be
// equal, which silently broke every dev release on 2026-07-25). If any link
// in this chain drops trigger_sha, exact verification either mis-binds or
// hard-fails on an empty value, so the whole wiring is pinned here.
const version = read('.github/workflows/version.yml');
const release = read('.github/workflows/release.yml');
const signAttest = read('.github/workflows/sign-attest.yml');
const publish = read('.github/workflows/release-publish.yml');
const verifier = read('scripts/release-generic-provenance.sh');

expect(version).toContain('trigger_sha: ${{ github.event.workflow_run.head_sha }}');
expect(release).toContain('trigger_sha:');
expect(release).toContain('trigger_sha: ${{ inputs.trigger_sha }}');
expect(signAttest).toContain('trigger_sha:');

// Substring checks are NOT enough: the first attempt at this fix put
// TRIGGER_SHA in the native-predicate step, whose script never reads it,
// while the step that actually runs verify-exact had none — a whole-file
// toContain() passed anyway and the next release died with the same silent
// exit 2. Assert the value reaches the env of the step that CONSUMES it.
const stepEnvFor = (workflow: string, needle: string): string => {
const lines = workflow.split('\n');
let start = -1;
for (let i = 0; i < lines.length; i += 1) {
if (/^\s+- name:/.test(lines[i])) start = i;
if (lines[i].includes(needle) && start >= 0) {
let end = start + 1;
while (end < lines.length && !/^\s+- name:/.test(lines[end])) end += 1;
return lines.slice(start, end).join('\n');
}
}
throw new Error(`no step found containing ${needle}`);
};

const verifyStep = stepEnvFor(signAttest, 'release-generic-provenance.sh verify-exact');
expect(verifyStep).toContain('TRIGGER_SHA:');
expect(verifyStep).toContain('${{ inputs.trigger_sha }}');
Comment thread
namastex888 marked this conversation as resolved.
Resolved

const gateStep = stepEnvFor(publish, 'generic_expected_sha');
expect(gateStep).toContain('TRIGGER_SHA:');

// The verifier compares the trigger commit, and refuses to run exact
// verification without a well-formed one.
expect(verifier).toContain('$run.head_sha == $trigger_sha');
expect(verifier).not.toContain('$run.head_sha == $source_sha');

// Stable records source_sha directly; automated channels cannot, so the
// generic descriptor is compared per channel.
expect(publish).toContain('generic_expected_sha="$SOURCE_SHA"');
expect(publish).toContain('generic_expected_sha="$TRIGGER_SHA"');
expect(publish).toContain('.sourceSha == $genericSourceSha');
});

test('release create and promotion paths retain the one-time convergence caveat', () => {
const workflow = read('.github/workflows/release-publish.yml');
const helper = read('scripts/reconcile-release-note.sh');
Expand Down
Loading