fix(kernel): export the entry hash that v2 chain links use - #2012
Conversation
audit.export reported every entry's content hash as BLAKE3 of its signing data. For a format-v1 entry that is the content hash. For a format-v2 entry the signing data is the signature wrapper of the entry hash, while chain links, chain heads and prune receipts use the SHA-256 entry hash of the canonical body. On a chain switched to v2, an exported entry's content_hash_hex therefore matched neither the next entry's previous_hash_hex nor the head hash in audit.heads, and a verifier following the export could not link the chain. The export now reports AuditEntry::content_hash(), which is unchanged for v1 entries. The wire-type documentation states the hash for each format and that a v1 signature covers whole seconds only. A kernel test exports a chain with two v1 entries followed by three v2 entries and checks each hash against the stored entry, the v2 signing wrapper, the links across the switch, and the head in the page and in audit.heads. It fails on the previous hash computation. Signed-off-by: Pavel Grigorenko <pavel@unicity-labs.com>
Changelog fragment for astrid-runtime#2011. Signed-off-by: Pavel Grigorenko <pavel@unicity-labs.com>
|
@joshuajbouw this is the v2 export-hash interaction flagged on #2005 (#2005 (comment)); it wasn't in the merged branch, so here it is on current main. |
|
Verified on 8ded51b: the mixed v1/v2 export regression passes. Restoring only the old BLAKE3(signing_data) calculation makes the unchanged test fail on the exported content hash, as expected. Restored the candidate and ran the full audit admin group: 9 passed, including paging, pruning, signed heads and access checks. Working tree is clean. The fix uses the existing format-aware AuditEntry::content_hash() without changing signature bytes or wire fields. Fork CI is approved and running; this is local verification, not a completed CI claim. |
|
|
The failed Runtime E2E run stopped after final registry removal, before the restart check. The saved final-remove response confirms the registry was absent; the shutdown helper then returned failure without recording the child exit status. That helper is unchanged by this PR. The underlying shutdown cause is not yet established. I preserved the first-run evidence and started one exact-head rerun to check repeatability. Separately, #2016 adds exit-status/forced-kill diagnostics without relaxing the shutdown check. A passing rerun would not establish that the original shutdown problem is fixed. |
joshuajbouw
left a comment
There was a problem hiding this comment.
Reviewed 8ded51b. The mixed-format export regression passes, fails when only the old hash calculation is restored, and the full audit admin group passes (9 tests). Export now uses the same canonical content hash as chain links. The exact-head Runtime E2E rerun passed. The earlier daemon shutdown failure is preserved separately; a green rerun does not establish its cause or fix it.
## Linked Issue Closes #2015. ## Summary Report why the runtime harness fails while stopping its daemon. This does not fix or waive the shutdown failure observed in #2012. ## Changes - Report PID, elapsed seconds, child exit status and whether the force-kill branch ran. - Preserve the existing wait, failure return and PID cleanup. - Exercise clean exit, nonzero exit and timeout using stubbed process operations; run these tests in the existing contract suite. - Do not print runtime logs or secrets. ## Verification Before the change, two of the three unchanged tests failed because failure diagnostics were empty. After the change all three pass. Bash syntax, ShellCheck and git diff --check pass. These tests prove the reporting contract, not the root cause of the real daemon failure. The full scripts/ci/test-release-contracts.sh suite also passes. Independent review accepted c4b7699 and reproduced the parent/head failure-reporting difference. Follow-up 3d01e42 addresses Copilot's test-coverage finding: both failure branches now require the correct PID, numeric elapsed seconds, exit status and force-kill flag, and clean exit requires empty stderr. All three focused tests pass on the follow-up. Required CI is pending on the new head. ## Test Plan Run python3 scripts/test_runtime_shutdown_diagnostics.py and shellcheck scripts/e2e/runtime-process-helpers.sh. On a future failing real harness run, use the emitted exit status and force-kill field to distinguish early daemon failure from a hung process. ## AI / Tool Assistance Assisted-by: Codex AI assistance implemented the diagnostics and tests. The complete diff was reviewed and the executable regression was run before and after the change. ## Checklist - [x] Linked to an issue - [x] CI-only change; no product changelog required - [x] Reviewed the complete diff - [x] Executed the focused regression - [x] Signed commit with matching DCO trailer --------- Signed-off-by: Joshua J. Bouw <jjb@unicity-labs.com>
Linked Issue
Closes #2011
Follow-up to #1996 and #2005.
Summary
audit.exportreported every entry'scontent_hash_hexasBLAKE3(signing_data). For a format-v1 entry that is its content hash. For a format-v2 entry the signing data is the signature wrapper of the entry hash, while chain links, chain heads and prune receipts use the SHA-256 entry hash of the canonical body. On a chain switched to v2, an exported entry's hash therefore matched neither the next entry'sprevious_hash_hexnor the head inaudit.heads, and a verifier following the export could not link the chain.The export now reports
AuditEntry::content_hash(), which is unchanged for v1 entries.Changes
astrid-kernel:audit.export.content_hash_hexis the entry's content hash in either format:BLAKE3(signing_data)for v1, the SHA-256 entry hash for v2.astrid-core: export wire types. Their documentation states which hash each format exports, that v2 signing data is the signature wrapper of that hash, and that only a v1 signature covers whole seconds.Verification
New kernel test
export_reports_the_hash_that_links_a_chain_switched_to_v2. It exports a chain with two v1 entries followed by three v2 entries and checks:audit.heads.It fails on the previous hash computation (the v2 hashes differ) and passes with this change.
Test suites:
astrid-core391 pass. The kernel lib passes 647 of 648 with--test-threads=6and umask 0022. The remaining failure needs a copy-on-write workspace backend and also fails onmain.Lint and changelog:
cargo fmt,cargo clippy --all-features --all-targets -- -D warningsonastrid-coreandastrid-kernel, andscripts/changelog.py check.AI / Tool Assistance
Assisted-by: Claude Code:claude-opus-5-5. Covers the fix, the test, the documentation and this description.
Assisted-by: Codex CLI. Review pass over the diff.
Checklist
changes/{issue}.{kind}.md(docs/CI-only may skip; release PRs roll fragments into the version section instead of adding one)Signed-off-bytrailer.