Skip to content

ci: semantic GitHub v1.21.16 release port - #26

Merged
AlexMikhalev merged 7 commits into
mainfrom
ci/v1.21.16-semantic-release-port
Sep 25, 2026
Merged

AlexMikhalev merged 7 commits into
mainfrom
ci/v1.21.16-semantic-release-port

Conversation

@AlexMikhalev

Copy link
Copy Markdown
Contributor

Summary

Semantically ports the accepted correlated v1.21.16 release stack onto GitHub main without merging the divergent Gitea history.

Preserves GitHub-specific release/security fixes #19–#25 byte-identical while integrating:

  • correlated stage-only release assets for terraphim-agent, terraphim-cli, and terraphim-grep
  • immutable signed inventory, promotion, rollback, and source-binding contracts
  • DEB/RPM nFPM producers and native lifecycle verification
  • managed-package receipt, guidance, and self-update refusal
  • strip-once canonical Linux bytes consumed unchanged downstream
  • portable Xcode lipo -verify_arch and path-safe RPM extraction
  • dual legacy/v2 manifest readers and producer compatibility
  • committed locked dependency graph for reproducible --locked builds

The final GitHub integration delta also removes two actionlint/ShellCheck failures without suppressions:

  • dynamic credential export uses export "${name?}"
  • checksum sealing uses deterministic NUL-safe filename collection with an explicit empty-stage guard

Source mapping

  • GitHub base: 2b10458b9f286ec5065a9a30dd54c38a1eb772a1
  • Accepted Gitea release stack merged in PR #332
  • Candidate: 50e1253545d848919ce5179c503de49f593df825
  • Tree: 7715105cb2164b7d15f28acb81ad381984d0edff

No .gitea workflows, runner changes, coverage history, or unrelated Gitea refactors are imported.

Verification

  • cargo metadata --locked --offline: pass
  • cargo check --locked --offline -p terraphim_agent: pass
  • cargo check --locked --offline -p terraphim_grep --features 'code-search openrouter': pass
  • cargo check --locked --offline --workspace --all-targets: pass
  • hooks tests: 43/43
  • agent library tests: 246/246
  • negative-contribution tests: 40/40
  • release workflow contracts: 36/36
  • release CI contracts: 5/5
  • full release contract suite: 97/97, one documented environmental skip
  • actionlint with ShellCheck 0.11.0: pass for all workflows
  • Bash syntax, Python AST, and git diff --check: pass
  • actionlint safety test proven RED under both unsafe-form mutations and GREEN on candidate

Independent review

  • Author route: GLM-5.2 after Kimi/MiniMax mapping
  • Full structural reviewer: Grok-4.5 via xAI OAuth — PASS, confidence 5/5
  • Final two-file actionlint delta reviewer: Grok-4.5 via xAI OAuth — PASS, confidence 5/5
  • Final findings: P0/P1/P2/P3 = 0/0/0/0

Release boundary

This PR lands producer source only. It does not tag, publish, promote, or mutate stable pointers. Release production and publication remain separately gated on exact-head hosted CI, merge ancestry, immutable sealing, and independent artifact verification.

Semantically integrate the v1.21.16 release stack on top of the
v1.21.14 GitHub base (2b10458), preserving every #19-#25 fix verbatim
and reconciling only the contracts that genuinely require GitHub-side
adaptation.

Preserved unchanged (byte-identical to 2b10458):
 - #19 finalize-prebuilt-release.yml, release-inputs/v1.21.14.json,
   zipsign-primary-public-key.base64, validate-release-inputs.py
 - #20 get-release-by-tag.sh
 - #21 secret isolation via tsm-production-release environment
   (declared on the restored producer's signing/sealing jobs)
 - #22 sign-macos-binary.sh PKCS12 validation
 - #23 one-use migration (already removed)
 - #24 portable macOS signature verification
 - #25 fresh-runner signature verification
 - scripts/sign-macos-binary.sh, finalize contract, all Ed25519 docs

Reconciled:
 - scripts/build-manifest.sh dual-mode: 3-arg stdout preserves the
   v1.21.14 finalizer's legacy v1 schema; 4-arg writes the strict v2
   candidate. tests/test_manifest_builder_compatibility.py guards the
   cross-contract path-key reconciliation.
 - .github/workflows/release-binaries.yml restores the producer from
   the Gitea candidate plus environment: tsm-production-release on the
   two production-credential jobs (#21 reconciliation).
 - .github/workflows/ci.yml adds the release contract suite, zipsign
   install, terraphim_update integration lane, the compat suite, and
   the client-packaging-contracts job.
 - r2-manifest-health.yml, publish-crates.yml (#95 guard) wholesale.
 - Cargo.toml workspace version 1.21.16 + the Gitea [patch.crates-io]
   registry policy; terraphim_agent/grep gain license-file + repository
   metadata (#246); grep inherits the workspace version.
 - Cargo.lock committed; regenerated for the GitHub graph and validated
   with cargo metadata --locked (online and offline).

Ported from the Gitea candidate: the correlated stage-only producer
scripts (promote/rollback/snapshot/validate-promotion/build-legacy/
create-deterministic-zip/stage-canonical-linux/validate-release-archive/
validate_release_binary/validate-r2-manifests), the DEB/RPM nFPM
producers and lifecycle tests, the release inventory assembler, the
terraphim_update managed-package/strict-v2 contract suite, both licence
files, docs/release-operator-checklist.md, and the seven release
contract tests.

API adaptation for terraphim_automata 1.21.0 (takes &Thesaurus where
1.20.x took owned Thesaurus) delivered by the accepted root patch:
 - crates/terraphim_hooks/Cargo.toml and src/replacement.rs ported
   byte-identical from gitea/main (1882f60); hooks 1.20.2 -> 1.21.16
   via version.workspace = true.
 - Mechanical borrow adaptations at every compiler-identified
   terraphim_automata call site, each matching the corresponding
   accepted gitea/main line: service.rs (3), mcp_tool_index.rs,
   commands/registry.rs (2), commands/markdown_parser.rs,
   guard_patterns.rs (3), learnings/capture.rs (annotate_with_entities
   + annotate_with_thesaurus signature &Thesaurus + local callers),
   learnings/procedure.rs, kg_validation.rs
   (validate_command_with_thesaurus &Thesaurus + local callers),
   main.rs extract_paragraphs, mcp_server/src/lib.rs (2),
   cli service.rs (4), cli main.rs evaluate + borrows,
   negative_contribution scanner.rs.
 - UpdateStatus::PackageManaged fallback arms ported from gitea/main:
   the exact 13-line arm in agent repl/handler.rs; cli main.rs
   check-update Ok(json) arm and update Err arm (package-managed
   refusal exits non-zero on the explicit update path).
 - Cargo.lock delta proven package-identical except the single
   terraphim_hooks 1.20.2 -> 1.21.16 member.

Gates green: cargo metadata --locked --offline; cargo check --locked
--offline -p terraphim_agent; -p terraphim_grep --features
'code-search openrouter'; --workspace --all-targets (all RC=0);
hooks 43/43; agent lib 246/246; negative_contribution 40/40;
96 release-contract tests; actionlint; bash -n; python AST;
git diff --check. Inherited-only limitations: fmt drift in
untouched files; cli ontology tests (8) need the Gitea #114 local
fixture; agent replace_feature_tests (5) need Gitea-only
docs/src/kg content -- both pre-existing at the 2b10458 base.

Refs: #19-#25, #95, #114, #118, #246, #247, #3336.
@AlexMikhalev
AlexMikhalev force-pushed the ci/v1.21.16-semantic-release-port branch from 50e1253 to cdbd0be Compare September 19, 2026 09:16
Alex Mikhalev added 2 commits September 25, 2026 16:00
Two independent fixes for the failures blocking hosted CI on this branch
(run 35434267810, the only hosted run against cdbd0be).

1. build job failed at `cargo fmt --all -- --check`, after the release
   workflow and sealing contract suites had already passed. Whitespace
   only: a `#[must_use]` attribute indented one level too deep under its
   doc comment in the terraphim-session-analyzer sources, plus rustfmt
   reflow and stray blank-line removal in terraphim_agent and
   terraphim_mcp_server. No semantic change; `cargo build --workspace`
   and `cargo fmt --all -- --check` both pass afterwards.

   The clippy gate errors that follow in the same job (`never used`
   helpers, needless_borrow, ptr_arg) are pre-existing on the untouched
   head and are NOT addressed here.

2. client-packaging-contracts failed in test_client_nfpm_arch.sh on
   "missing RPM arch mismatch diagnostics: RPM payload extraction
   failed". The extraction itself succeeded: the captured log shows all
   five payload members and "26 blocks" extracted. rpm2cpio and cpio are
   not provisioned by the packaging job, so verify_rpm took the
   docker_rpm_tool fallback path instead of the production host path the
   arch suite exists to protect. Install rpm2cpio, cpio and rpm
   explicitly, with a post-install presence assertion for each, so the
   suite exercises the host branch deterministically.

Verification (all with the pinned toolchain CI uses: nFPM 2.47.0
checksum-verified, Python 3.12, actionlint 1.7.12 paired with ShellCheck
0.11.0, REQUIRE_TOOLS=1):
 - cargo fmt --all -- --check: pass
 - cargo build --workspace: pass
 - actionlint .github/workflows/ci.yml: pass
 - tests.test_release_binaries_workflow_contract: 36/36
 - test_client_nfpm.sh, _arch, _policy, _static_lint, _strip,
   test_verify_nfpm.sh, test_assemble_client_release_inventory.sh:
   all pass

Refs #26
The install step added in 9066e6a failed its own post-install assertion
on the first hosted run (36153626510): "rpm2cpio missing after install",
exit 1, before any contract suite ran.

rpm2cpio has no --version or --help flag — it takes an RPM path as its
sole positional argument, so `rpm2cpio --version` reports
"--version: No such file or directory" and exits 1 regardless of whether
the tool is installed. The assertion was therefore testing for a flag
rather than for the binary. Probe with `command -v` instead; cpio and rpm
do support --version and keep that check.

Verified locally: the corrected block exits 0 with all three tools
present, and still fails closed when rpm is removed from PATH.

Refs #26
AlexMikhalev pushed a commit that referenced this pull request Sep 25, 2026
Hosted run 36153935369 still failed the arch suite after the tooling step
was added, with the same message:

  FAIL: missing RPM arch mismatch diagnostics: RPM payload extraction
  failed ... (rpm2cpio | cpio --no-absolute-filenames -idmv):
    cpio: Removing leading `/' from member names
    usr/bin/terraphim-agent
    ... all five members ...
    26 blocks

Every payload member extracted and the archive reached its trailer, yet
verify_rpm rejected the package. Root cause: rpm 4.17's rpm2cpio exits 1
on nFPM 2.47 RPMs while writing a complete, correct payload and printing
nothing to stderr. Reproduced on both this host and the ubuntu-24.04 CI
image: `rpm2cpio pkg > out.cpio` leaves a valid 13 KB stream ending in
TRAILER!!!, `cpio` lists it cleanly, and `rpm -K` reports "digests OK",
while rpm2cpio itself returns 1. The arch and payload-SHA checks never
ran because the pipeline status alone aborted verification.

verify_rpm now decides on what extraction produced: the extract directory
is recreated, cpio diagnostics are still surfaced when the pipeline
returns nonzero, and failure is reported only when no binary appears.
Fail-closed is preserved and strengthened downstream — the existing
EXPECTED_SHA comparison and the arch check still gate acceptance, and a
truncated payload produces no binary at all.

Tests:
 - test_verify_rpm_accepts_complete_payload_despite_rpm2cpio_exit_status
   new: stubs a complete archive on stdout with rpm2cpio returning 1.
   Proven RED against the previous status-trusting logic and GREEN now.
 - test_verify_rpm_host_branch_surfaces_extraction_diagnostics updated:
   it asserted the old "RPM payload extraction failed" wording, which
   encoded the very assumption being corrected. It now asserts the
   payload-based message while still requiring the cpio diagnostic.

Verified with the pinned toolchain (nFPM 2.47.0 checksum-verified,
Python 3.12, actionlint 1.7.12 with ShellCheck 0.11.0, REQUIRE_TOOLS=1):
 - test_release_binaries_workflow_contract 36/36
 - test_client_nfpm.sh, _arch, _policy, _static_lint, _strip,
   test_verify_nfpm.sh, test_assemble_client_release_inventory.sh: pass
 - fail-closed confirmed on truncated payload, garbage input, and a
   tampered extracted binary

Refs #26
Hosted run 36153935369 still failed the arch suite after the tooling step
was added, with the same message:

  FAIL: missing RPM arch mismatch diagnostics: RPM payload extraction
  failed ... (rpm2cpio | cpio --no-absolute-filenames -idmv):
    cpio: Removing leading `/' from member names
    usr/bin/terraphim-agent
    ... all five members ...
    26 blocks

Every payload member extracted and the archive reached its trailer, yet
verify_rpm rejected the package. Root cause: rpm 4.17's rpm2cpio exits 1
on nFPM 2.47 RPMs while writing a complete, correct payload and printing
nothing to stderr. Reproduced on both this host and the ubuntu-24.04 CI
image: `rpm2cpio pkg > out.cpio` leaves a valid 13 KB stream ending in
TRAILER!!!, `cpio` lists it cleanly, and `rpm -K` reports "digests OK",
while rpm2cpio itself returns 1. The arch and payload-SHA checks never
ran because the pipeline status alone aborted verification.

verify_rpm now decides on what extraction produced: the extract directory
is recreated, cpio diagnostics are still surfaced when the pipeline
returns nonzero, and failure is reported only when no binary appears.
Fail-closed is preserved and strengthened downstream — the existing
EXPECTED_SHA comparison and the arch check still gate acceptance, and a
truncated payload produces no binary at all.

Tests:
 - test_verify_rpm_accepts_complete_payload_despite_rpm2cpio_exit_status
   new: stubs a complete archive on stdout with rpm2cpio returning 1.
   Proven RED against the previous status-trusting logic and GREEN now.
 - test_verify_rpm_host_branch_surfaces_extraction_diagnostics updated:
   it asserted the old "RPM payload extraction failed" wording, which
   encoded the very assumption being corrected. It now asserts the
   payload-based message while still requiring the cpio diagnostic.

Verified with the pinned toolchain (nFPM 2.47.0 checksum-verified,
Python 3.12, actionlint 1.7.12 with ShellCheck 0.11.0, REQUIRE_TOOLS=1):
 - test_release_binaries_workflow_contract 36/36
 - test_client_nfpm.sh, _arch, _policy, _static_lint, _strip,
   test_verify_nfpm.sh, test_assemble_client_release_inventory.sh: pass
 - fail-closed confirmed on truncated payload, garbage input, and a
   tampered extracted binary

Refs #26
@AlexMikhalev
AlexMikhalev force-pushed the ci/v1.21.16-semantic-release-port branch from 7f9b4fb to 28354b8 Compare September 25, 2026 15:43
Alex Mikhalev and others added 3 commits September 25, 2026 16:53
Run 36156158322 surfaced the final gate the workflow was missing: every
"cargo fmt" / "cargo clippy" / "cargo build" / "cargo test" step fails
out of the box because the workspace pins twelve private-registry deps
(Cargo.toml lines 82-85 and others) and the runner has no token for the
terraphim registry.

```
error: failed to load source for dependency `terraphim-markdown-parser`
  unable to update registry `terraphim`
  no token found for `terraphim`
```

The secret `CARGO_REGISTRIES_TERRAPHIM_TOKEN` exists on the repo and is
already used by release-binaries.yml (line 232). ci.yml simply never
mapped it. Add it at the build-job level so the build, updater
integration tests, and contract steps can resolve private-registry
crates.

The client-packaging-contracts job does not need it: its suites shell
out to nFPM and shell fixtures only, never to cargo.

Refs #26
Pre-existing failures that kept every recent ci.yml run red (#338):

- clippy::ptr_arg: set_hermetic_env and run_user_prompt_submit took
  &PathBuf; take &Path instead.
- clippy::needless_borrow: annotate_with_thesaurus passed &&Thesaurus
  into find_matches.
- dead_code: score_entry_relevance, ScoredEntry + format_suggestion,
  shared_learning_from_entry and suggest_learnings are production API
  whose only caller, main.rs::run_suggest_command, is
  #[cfg(feature = "shared-learning")]. Mark them #[allow(dead_code)]
  with that justification, mirroring with_correction in the same file.

cargo clippy --workspace --all-targets -- -D warnings exits 0 on
rustc 1.98.1; terraphim_agent lib tests (246) and
user_prompt_submit_tests (4) pass.

Refs #338
test_download_creates_output_file, test_download_result_success and
test_download_silent_local_file fetched https://git.terraphim.cloud/api/v1/version
from CI, which the hosted runner resolves to a 403. Serve the same
requests from a real std::net::TcpListener loopback server, the pattern
already used by tests/{manifest,r2_update,managed_mode}.rs, and drop the
now-unused can_connect helper. A 10ms server-side delay keeps the
recorded-duration assertion meaningful on loopback.

Full workspace lib lane passes locally on rustc 1.98.1.

Refs #337
@AlexMikhalev
AlexMikhalev merged commit e814910 into main Sep 25, 2026
2 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