The update guard compared the archive version with PROGRAM_VERSION using shell
string ordering. Both halves were wrong.
PROGRAM_VERSION is a constant describing the bootstrap source tree ("0.2.0-dev"),
never the deployed component, so it could not represent what is installed. The
cross-role compatibility check compared it with a manifest field such as
"v0.1.0-alpha.9"; those can never be equal, so update-control on a host that also
runs the agent always failed. The downgrade guard compared the same mismatched
pair and passed only by accident, because "v" sorts above "0" in ASCII.
String ordering is also wrong for the version scheme in use: "0.1.0-alpha.10"
sorts below "0.1.0-alpha.9", so the next release after the ninth would have been
rejected as a downgrade.
- record the installed version per role at install and update time, and compare
against that instead of PROGRAM_VERSION;
- order versions with sort -V after stripping the leading "v", so prerelease
numbering and tag prefixes compare correctly;
- treat an unknown peer version as a warning rather than a failure, because
installations predating version recording have nothing to compare against;
- guard all of the above in the bootstrap contract test, including the six
ordering cases and a check that the lexicographic comparison is not restored.
Verified by deliberately reintroducing each defect: lexicographic comparison,
sort without -V, and a missing version record are all caught by the contract test.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- test-bootstrap-contract: Generate signed manifest.json with cosign test key
- systemd smoke tests: Pass SMM_ALLOW_UNSIGNED=1 fallback when manifest is missing (for CI PR runs)
- UpdateService: manifest version must match release tag_name (prevents cross-version attacks)
- UpdateService: corrupted MSIX deleted immediately on hash mismatch
- UpdateService: TraceSource logging for all verification steps
- UpdateService: Trust anchor constants with docs/release-policy.md reference
- Bootstrap: docs/release-policy.md reference next to identity constants
- Test csproj: add UpdateService.cs Compile Include (tests won't compile without this)
- Fixed archive hash extraction from manifest using archive basename
- Added version compatibility checks for Control/Agent/helper in update_role
- Expanded UpdateService tests to 4 unit tests
- Verified against alpha.8 manifest
- permissions: contents: write moved from step to job level in
linux-release.yml (both 'bootstrap' and 'publish' jobs) and
windows-release.yml ('package' job); step-level permissions key
is not valid in GitHub Actions schema
- Remove redundant SBOM generation from 'bootstrap' job (no .NET
setup there; 'publish' job already covers the full solution)
- Remove '|| true' from SBOM steps — failures are now visible
- Add SBOM JSON to upload-artifact path and release files in
linux-release.yml (publish job) and windows-release.yml
Verified with actionlint 1.7.7 — 0 errors on all 5 workflow files
Adopt the reviewed parts of the external vision document as repository
specifications, and record the work-order gates that keep unimplemented
subsystems from starting before their prerequisites are closed.
- product-horizons.md: four horizons with hard exit criteria; Horizon 0
closes physical acceptance, signed delivery, the Monitor role and
certificate rotation before anything new begins.
- approval-policies.md: nine approval modes over the existing binary
confirmation, mapped onto ProvisioningJob, TTL and execution grants.
- integration-kagent.md: capability model split into read, request and
never-grantable; untrusted-executor invariant for KAgent Worker;
SO_PEERCRED on the discovery socket; API designed against entities
that exist today.
- security-model.md: untrusted executors on a Node, the public web
surface decision that must be recorded before that work starts, and
never-grantable capabilities.
- roadmap.md: stages 14-18 for the adopted scope, pinned to horizons.
All three new documents state that nothing in them is implemented.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>