Repository navigation
fix: canonicalize desktop runtime manifests - #364
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
WalkthroughThe change adds canonical JSON utilities, a runtime manifest verification CLI, desktop verification tests, and release workflow coverage. ChangesRuntime manifest validation
Estimated code review effort: 3 (Moderate) | ~25 minutes Mergeability Score: ⚪ Minimal · up to The change canonicalizes signed runtime manifests and adds exact verification before publication; the previously reported clean-checkout blocker is addressed at the current head, so no actionable merge-blocking risk remains after normal checks and review. Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
| Filename | Overview |
|---|---|
| .github/workflows/release.yml | Adds the exact-consumer verification step before publication, while the previously reported mutable third-party action references remain. |
| internal/desktoprelease/canonical_json.go | Adds number-preserving generic JSON re-encoding so object keys are recursively sorted and output remains compact. |
| desktop/src-tauri/src/bin/runtime_manifest_check.rs | Adds a fail-closed CLI that verifies the signed manifest and expected version for every requested target. |
| desktop/src-tauri/src/runtime/artifacts.rs | Refactors signing fixtures and adds regression coverage for rejecting correctly signed but non-canonical manifest bytes. |
| internal/config/release_config_test.go | Verifies signing, exact-consumer validation, publication ordering, credentials, and the shipping-target matrix. |
| internal/desktoprelease/release_test.go | Adds canonical-byte assertions for both generated release manifests. |
Sequence Diagram
sequenceDiagram
participant Producer as Go release producer
participant Signer as Manifest signer
participant Verifier as Desktop verifier CLI
participant R2 as Release storage
Producer->>Producer: Canonicalize runtime.json
Producer->>Signer: Pass canonical bytes
Signer-->>Producer: runtime.json.minisig
Producer->>Verifier: Manifest, signature, version, targets
loop Every shipping target
Verifier->>Verifier: Verify signature and canonical bytes
Verifier->>Verifier: Validate artifact and version
end
Verifier-->>Producer: Verification succeeds
Producer->>R2: Publish payloads and manifests
Reviews (2): Last reviewed commit: "fix: track runtime manifest checker" | Re-trigger Greptile
| - uses: dtolnay/rust-toolchain@stable | ||
|
|
||
| - uses: Swatinem/rust-cache@v2 | ||
| with: |
There was a problem hiding this comment.
Mutable actions in release job
The new Rust toolchain and cache steps use mutable @stable and @v2 references before this job accesses release, signing, and R2 credentials. Pinning both actions to full commit SHAs prevents upstream tag movement from silently changing code executed inside this privileged publication boundary.
How this was verified: The mutable actions run before subsequent steps receive the release token, Tauri signing key, and R2 publication credentials.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/config/release_config_test.go`:
- Around line 549-561: Update the ordering assertions around the workflow string
in the relevant release-config test so they inspect only the desktop release
job, not the complete workflow. Parse or isolate that job before locating the
signing, verification, and publication steps, then preserve the existing
presence and ordering checks within that scoped job.
- Around line 549-550: Add the missing runtime_manifest_check.rs source declared
by the compo zy-runtime-manifest-check binary, and narrow or remove the
repository bin ignore rule so the file is tracked. Update the release-order test
around signManifest and verifyManifest to inspect only the desktop-publish job,
then assert the checker runs before scripts/publish-desktop-release.sh within
that job.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 67e4c389-11bc-40fb-a411-0c231226e8aa
⛔ Files ignored due to path filters (4)
.github/workflows/release.ymlis excluded by!**/*.ymldesktop/src-tauri/Cargo.tomlis excluded by!**/*.tomldocs/qa/reports/2026-08-12-runtime-manifest-verification.mdis excluded by!**/*.mddocs/qa/scenarios/APP-install-first-run-provision.mdis excluded by!**/*.md
📒 Files selected for processing (5)
desktop/src-tauri/src/runtime/artifacts.rsinternal/config/release_config_test.gointernal/desktoprelease/canonical_json.gointernal/desktoprelease/manifest.gointernal/desktoprelease/release_test.go
💤 Files with no reviewable changes (1)
- internal/desktoprelease/manifest.go
| signManifest := strings.Index(workflow, "scripts/sign-runtime-manifest.sh") | ||
| verifyManifest := strings.Index(workflow, "--bin compozy-runtime-manifest-check") |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
fd -HI -a '^(Cargo\.toml|runtime_manifest_check\.rs)$' .
fd -HI -a '^Cargo\.toml$' . -x rg -n -C 3 'compozy-runtime-manifest-check|runtime_manifest_check' {}
git ls-files --error-unmatch -- ':(glob)**/runtime_manifest_check.rs'
git status --ignored --short --untracked-files=all | rg 'runtime_manifest_check\.rs|/bin/' || trueRepository: compozy/compozy
Length of output: 451
🏁 Script executed:
#!/usr/bin/env bash
set -u
printf '%s\n' '--- candidate files ---'
fd -HI -a 'runtime_manifest_check\.rs|Cargo\.toml|release.*\.ya?ml|.*workflow.*\.ya?ml' .
printf '%s\n' '--- Cargo references ---'
rg -n -C 5 'compozy-runtime-manifest-check|runtime_manifest_check' --glob 'Cargo.toml' --glob '*.rs' --glob '*.ya?ml' --glob '*.yaml' --glob '*.yml' .
printf '%s\n' '--- tracked source status ---'
git ls-files -- '**/runtime_manifest_check.rs'
git status --ignored --short --untracked-files=all | rg 'runtime_manifest_check\.rs|/bin/' || true
git check-ignore -v --no-index /home/jailuser/git/desktop/src-tauri/src/bin/runtime_manifest_check.rs || true
printf '%s\n' '--- Cargo manifest ---'
cat -n /home/jailuser/git/desktop/src-tauri/Cargo.toml | sed -n '55,85p'
printf '%s\n' '--- release test ---'
cat -n internal/config/release_config_test.go | sed -n '530,580p'
printf '%s\n' '--- workflow references ---'
rg -n -C 8 'sign-runtime-manifest|compozy-runtime-manifest-check|manifest' .github internal/config --glob '*.yml' --glob '*.yaml' --glob '*.go'Repository: compozy/compozy
Length of output: 18668
🏁 Script executed:
#!/usr/bin/env bash
set -u
cat -n .github/workflows/release.yml | sed -n '850,975p'
printf '%s\n' '--- relevant workflow occurrences ---'
rg -n '^[[:space:]]{2}[A-Za-z0-9_-]+:|scripts/sign-runtime-manifest\.sh|--bin compozy-runtime-manifest-check|scripts/publish-desktop-release\.sh' .github/workflows/release.yml
printf '%s\n' '--- ignore rule ---'
cat -n .gitignore | sed -n '1,15p'Repository: compozy/compozy
Length of output: 7612
Commit runtime_manifest_check.rs and scope the release-order test.
desktop/src-tauri/Cargo.tomldeclarescompozy-runtime-manifest-checkwith sourcedesktop/src-tauri/src/bin/runtime_manifest_check.rs, but that source is absent and matches the repository-widebin/ignore rule. Thedesktop-publishjob invokes it beforescripts/publish-desktop-release.sh, so the release job cannot build the checker. Add the source and narrow or remove the ignore rule.- The test compares positions in the full workflow text. It does not prove that the commands belong to the same
desktop-publishjob. Scope the assertion to that job or parse the workflow structure.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@internal/config/release_config_test.go` around lines 549 - 550, Add the
missing runtime_manifest_check.rs source declared by the compo
zy-runtime-manifest-check binary, and narrow or remove the repository bin ignore
rule so the file is tracked. Update the release-order test around signManifest
and verifyManifest to inspect only the desktop-publish job, then assert the
checker runs before scripts/publish-desktop-release.sh within that job.
| signManifest := strings.Index(workflow, "scripts/sign-runtime-manifest.sh") | ||
| verifyManifest := strings.Index(workflow, "--bin compozy-runtime-manifest-check") | ||
| publishFeed := strings.Index(workflow, "scripts/publish-desktop-release.sh") | ||
| if signManifest == -1 || verifyManifest == -1 || publishFeed == -1 { | ||
| t.Fatal( | ||
| "desktop release workflow is missing candidate manifest signing, " + | ||
| "consumer verification, or publication", | ||
| ) | ||
| } | ||
| if signManifest > verifyManifest || verifyManifest > publishFeed { | ||
| t.Fatal("desktop release workflow must verify signed candidate manifest bytes before publication") | ||
| } | ||
| verification := workflow[signManifest:publishFeed] |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Scope the ordering check to the release job.
Line 549 searches the complete workflow text. A checker command in another job can satisfy this test while the publishing job does not wait for verification.
Parse the workflow, or isolate the release job, before comparing the signing, verification, and publication steps.
As per path instructions, tests must verify behavior outcomes on critical paths.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@internal/config/release_config_test.go` around lines 549 - 561, Update the
ordering assertions around the workflow string in the relevant release-config
test so they inspect only the desktop release job, not the complete workflow.
Parse or isolate that job before locating the signing, verification, and
publication steps, then preserve the existing presence and ordering checks
within that scoped job.
Source: Path instructions
Summary
Closes #362.
Root cause
The Go release producer serialized
runtime.jsonfrom structs. Go preserves struct-field order, while the Rust desktop verifier recursively sorts object keys and requires those canonical bytes to match the signed input exactly. Beta.13 therefore carried a valid signature and valid archive metadata but was rejected as non-canonical before provisioning could install the runtime.Changes
compozy-runtime-manifest-checkCLI and invokes it after signing and before upload fordarwin-aarch64,darwin-x86_64, andlinux-x86_64./bin/, so Rust's standardsrc/bin/source directory is tracked. Commit2c7499d7fixes the missing-source failure from Actions job94311211872.Release notes
🐛 Bug Fixes
QA
Status: ready with blocked items at the code-contract level; not ready for signed package acceptance.
Coverage: Lea's macOS and Linux first-run charters were evaluated through the package precondition boundary in an isolated targeted QA lab.
Blocked / needs human: build the next signed candidate from this branch, then walk the DMG on a clean macOS machine and the AppImage on a clean Linux machine through install, provisioning, relaunch, single-daemon verification, and healthy
compozy status.Process hygiene: the QA evidence audit passed, and teardown completed with
clean: trueand no survivors.Full report:
2026-08-12-runtime-manifest-verification.mdTest plan
CGO_ENABLED=1 go test -race ./internal/desktoprelease ./internal/configcargo fmt --manifest-path desktop/src-tauri/Cargo.toml --all -- --checkcargo clippy --manifest-path desktop/src-tauri/Cargo.toml --all-targets --all-features -- -D warningscargo test --manifest-path desktop/src-tauri/Cargo.toml runtime::artifacts::tests::cargo test --locked --manifest-path desktop/src-tauri/Cargo.toml --bin compozy-runtime-manifest-checkmake desktop-lintmake desktop-testgit ls-tree -r --name-only HEAD -- desktop/src-tauri/src/bin/runtime_manifest_check.rsclean: true)make gate-fullwas not completed at the operator's requestCompozy Impact Audit
compozy__*tool IDs, descriptors, schemas, capability gates, and CLI/API fallbacks; this change is confined to offline desktop release metadata and publication.config.toml; no runtime extension surface or configuration key changes.skills/compozy/; public tools, CLI paths, hook events, capabilities, extension resources, and task/memory/network behavior are unchanged.Summary by CodeRabbit
Bug Fixes
Tests