VA-60: publish minisign-signed meshagent-<id> matching the server fetcher contract #65

Merged
nrupard merged 2 commits from feat/VA-60-publish-meshagent into main 2026-06-16 19:53:06 +02:00
Owner

Makes the agent publish workflow emit exactly what the vervain-server fetcher consumes, so a configured server fetches and serves a working Linux x86_64 agent and device enrollment succeeds. Builds on VA-57 (which already signed and published the meshagent-6 + .minisig pair) and on the VA-58 key-custody design.

Changes

  • Sign both published binaries. The minisign step now signs the descriptive vervain-agent-x86_64-... artifact in addition to meshagent-6, so every binary in the package carries a minisign signature (not just a SHA-256 checksum). Both verify against the same VA-58 publisher public key.
  • Publish to two version coordinates. Each build uploads the full file set to the pinned X.Y.Z (immutable, 409-tolerant) and to a moving stable tag. The generic registry refuses to overwrite, so the stable path deletes each file (HTTP 204, or 404 on first publish) before re-uploading, so stable always points at the latest main build. stable is the fetcher's default pin, so staging tracks the newest agent with no per-release config bump; a pinned X.Y.Z stays available for a frozen binary.
  • Package name stays vervain-agent (operator-configurable on the server via VERVAIN_AGENT_FETCHER_PACKAGE), keeping the descriptive artifacts and the meshagent-<id> pair in one package.
  • Document the operator config. docs/agent-package-distribution.md gains a server-fetcher configuration section with the exact VERVAIN_AGENT_FETCHER_* values (base, owner, package, version, agent-ids, publickey, read:package token for the private namespace), the fail-closed verification behaviour, and an explicit coverage note: only id 6 is built today, pin VERVAIN_AGENT_FETCHER_AGENT_IDS=6 until cross-target builds land.

Acceptance criteria

  • AC1 (minisig for every published artifact): done - both binaries signed.
  • AC2 (meshagent-6 + .minisig under agreed owner/package/version): done - published to pinned X.Y.Z and stable.
  • AC3/AC4 (server fetches + verifies at boot, tampered fails closed): validated against a configured vervain-server and a live registry, outside this repo's CI.
  • AC5 (public key + coordinates documented): done - server-fetcher configuration section.
  • AC6 (id coverage stated): done - id 6 only, pin VERVAIN_AGENT_FETCHER_AGENT_IDS=6.

Validation

No Rust touched. The workflow's embedded nu and the YAML were validated here by parse + runtime checks (nu --ide-check clean, list-iteration/indexing and not-in exercised, the workflow YAML parses to 8 steps). The CI run itself exercises the build/sign/publish end to end on merge to main.

Decisions confirmed with the maintainer: moving stable + pinned X.Y.Z; keep package vervain-agent; sign both binaries.

#VA-60

Makes the agent publish workflow emit exactly what the `vervain-server` fetcher consumes, so a configured server fetches and serves a working Linux x86_64 agent and device enrollment succeeds. Builds on VA-57 (which already signed and published the `meshagent-6` + `.minisig` pair) and on the VA-58 key-custody design. ## Changes - Sign both published binaries. The minisign step now signs the descriptive `vervain-agent-x86_64-...` artifact in addition to `meshagent-6`, so every binary in the package carries a minisign signature (not just a SHA-256 checksum). Both verify against the same VA-58 publisher public key. - Publish to two version coordinates. Each build uploads the full file set to the pinned `X.Y.Z` (immutable, 409-tolerant) and to a moving `stable` tag. The generic registry refuses to overwrite, so the `stable` path deletes each file (HTTP 204, or 404 on first publish) before re-uploading, so `stable` always points at the latest main build. `stable` is the fetcher's default pin, so staging tracks the newest agent with no per-release config bump; a pinned `X.Y.Z` stays available for a frozen binary. - Package name stays `vervain-agent` (operator-configurable on the server via `VERVAIN_AGENT_FETCHER_PACKAGE`), keeping the descriptive artifacts and the `meshagent-<id>` pair in one package. - Document the operator config. `docs/agent-package-distribution.md` gains a server-fetcher configuration section with the exact `VERVAIN_AGENT_FETCHER_*` values (base, owner, package, version, agent-ids, publickey, read:package token for the private namespace), the fail-closed verification behaviour, and an explicit coverage note: only id 6 is built today, pin `VERVAIN_AGENT_FETCHER_AGENT_IDS=6` until cross-target builds land. ## Acceptance criteria - AC1 (minisig for every published artifact): done - both binaries signed. - AC2 (`meshagent-6` + `.minisig` under agreed owner/package/version): done - published to pinned `X.Y.Z` and `stable`. - AC3/AC4 (server fetches + verifies at boot, tampered fails closed): validated against a configured vervain-server and a live registry, outside this repo's CI. - AC5 (public key + coordinates documented): done - server-fetcher configuration section. - AC6 (id coverage stated): done - id 6 only, pin `VERVAIN_AGENT_FETCHER_AGENT_IDS=6`. ## Validation No Rust touched. The workflow's embedded nu and the YAML were validated here by parse + runtime checks (`nu --ide-check` clean, list-iteration/indexing and `not-in` exercised, the workflow YAML parses to 8 steps). The CI run itself exercises the build/sign/publish end to end on merge to main. Decisions confirmed with the maintainer: moving `stable` + pinned `X.Y.Z`; keep package `vervain-agent`; sign both binaries. #VA-60
feat(ci): publish meshagent-<id> matching the server fetcher contract (VA-60)
Some checks failed
Check / clippy + fmt + tests (pull_request) Has been cancelled
1963253910
VA-57 already signed and published the meshagent-6 + .minisig pair the vervain-server fetcher reads. VA-60 closes the remaining coordinate and coverage gaps so a configured server fetches and serves a working Linux x86_64 agent and device enrollment succeeds.

Sign both published binaries. The sign step now produces a detached minisign signature for the descriptive vervain-agent-x86_64-... artifact as well as meshagent-6, so every binary in the package carries a minisign signature (a SHA-256 checksum is not a signature). Both verify against the same VA-58 publisher public key.

Publish to two version coordinates. Each build uploads the full file set to the pinned X.Y.Z (immutable, 409-tolerant as before) and to a moving `stable` tag. Because Forgejo's generic registry refuses to overwrite, the `stable` path deletes each file (204, or 404 on first publish) before re-uploading it, so `stable` always points at the latest main build. `stable` is the coordinate the server fetcher pins by default, so staging tracks the newest agent with no per-release config bump; pin a specific X.Y.Z for a frozen binary.

Package name stays `vervain-agent` (the fetcher package is operator-configurable; the descriptive artifacts live there too), so the server sets VERVAIN_AGENT_FETCHER_PACKAGE=vervain-agent explicitly.

Document the operator config. docs/agent-package-distribution.md gains a server-fetcher configuration section with the exact VERVAIN_AGENT_FETCHER_* values (base, owner, package, version, agent-ids, publickey, read:package token for the private namespace), the fail-closed verification behaviour, and an explicit id-coverage note: only id 6 is built today, pin VERVAIN_AGENT_FETCHER_AGENT_IDS=6 until cross-target builds land.

The server-side fetch + verify ACs (boot fetch, signature verifies, tampered fails closed, /meshagents/6 serves) are validated against a configured vervain-server and a live registry, outside this repo's CI. Workflow nu and YAML validated by parse + runtime checks here.

#VA-60

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
docs(fetcher): correct VERVAIN_AGENT_FETCHER_* env names against the server (VA-60)
All checks were successful
Check / clippy + fmt + tests (pull_request) Successful in 8m6s
Create release / Create release from merged PR (pull_request) Has been skipped
462f620f9c
Review caught two operator-facing env var names that did not match the vervain-server source of truth (.env.example + agent_fetcher_seed.rs); a paste of either would be silently ignored and leave the fetcher unconfigured.

- VERVAIN_AGENT_FETCHER_BASE -> VERVAIN_AGENT_FETCHER_BASE_URL.
- VERVAIN_AGENT_FETCHER_PUBLICKEY -> VERVAIN_AGENT_FETCHER_PUBLIC_KEY.

Add the secret-file variants the server supports (_PUBLIC_KEY_FILE, _TOKEN_FILE) and the optional _REFRESH_INTERVAL_SECS, and recommend the _FILE forms in production so the key and token are not baked into the environment.

Clarify the package-name note: the server seed requires VERVAIN_AGENT_FETCHER_PACKAGE (no default); the `meshagent` in the server .env.example is only illustrative, so set it to `vervain-agent` to match this publisher.

Document that the moving `stable` delete-then-reupload is not atomic, and that the fetcher's fail-closed behaviour degrades this to "serves the previous good binary" rather than ever serving a partial or unsigned artifact.

#VA-60

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
nrupard deleted branch feat/VA-60-publish-meshagent 2026-06-16 19:53:06 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/vervain-agent!65
No description provided.