Skip to content

Preserve one-command Dev composition without enrolling local publishers #5341

Open

Description

@auser

Decision

mvmctl run --compose PACK.TOML should remain a one-command first-use transient development run. Keep #5301 explicit host-signer enrollment for installable or later-launchable local bundles. A host signature proves origin, not operator approval or release authority. Do not add an enrollment exception to the normal bundle registry, installed launch, or publisher trust store.

Implementation boundary

  • The composed archive and verified filesystem cache are data, not authorization. For every cold or repeat run, reverify the authored recipe, base/PR evidence, host-local signature, selected bytes and policy, then mint an invocation-private, one-use Dev capability bound to the exact archive digest, host signer, selected kernel/base proof, process/user, and expiry.
  • Carry that capability from the CLI to admission and launch without converting it to an installed bundle reference. The host must check it at the actual boot boundary; the installed registry, rematerialization, export, claim and later launches must never accept it. Fail closed on prod/fleet posture, external signing, changed bytes, expired/replayed capability, incomplete admission or a different host/user.
  • Do not allow a cache hit to reuse authorization. It must reverify and mint a new one-use capability. The ordinary bundle install path remains enrollment-gated.
  • Test cold and repeat CLI guest output, a measured cache hit, and denial at every conversion to durable authority. No acceptance from direct-VMM-only or synthetic-signature-only evidence.

Longer-term direction

Separately signed, independently revocation-checked base and full guest runtime plus authenticated application/runtime/tool graph, actual selected argv and effective admitted policy must bind a protected-pipeline-signed self-contained bundle for production. The transient Dev capability is not a shortcut or trust root for that release path. Keep schema v1 and published pack/image versions unchanged; do not advance images.lock or raise the footprint ratchet on this issue.

Related draft #5326 contains the current development composer; #5301 guards durable local bundle enrollment. The PR-only Hetzner CLI test currently reaches admission and Firecracker but the guest agent does not become reachable; do not mark this issue complete before a real guest-value/cache-hit witness and required gates pass.

Activity

  1. auser commented on Nov 11, 2026

    @auser
    CollaboratorAuthor

    Integration update: the three commits from #5301 were cherry-picked onto draft #5326 at cb7333c185 for testing; this does not merge either PR into main. The enrolled-host gate is active at archive ingress, pinned admission and installed-launch/rematerialization, and focused CLI, client and core tests passed. As expected, this makes the existing run --compose install-to-slot path refuse a virgin host. The distinct invocation-private transient Dev launch/capability path is still not implemented, so do not count a one-command success or close this issue. No publisher trust bypass was added. A real CLI guest-value/cache-hit witness is also still blocked by guest-agent readiness on the PR-only KVM test.

  2. auser commented on Nov 11, 2026

    @auser
    CollaboratorAuthor

    Dev-only one-command witness on draft #5326 (5be9d21fa2, not main): the invocation-private composition now stages and admits without enrolling the host key or creating an installed bundle. The guest-agent activation gap and missing sealed /etc/mvm/entrypoint are fixed. The normal installed path remains enrollment-gated (#5301).

    On authorized x86_64 Hetzner KVM, the PR-only CLI and signed base from Actions run 43119905868 plus the same-PR signed guest-runtime quartet from run 43108383169 produced COMPOSED_GUEST_VALUE=print('ready') twice via mvmctl run --compose and Firecracker: cold 34 s (assembled and cached composition 8fec2d4d…), repeat 27 s (authenticated cached composition 8fec2d4d…). Both exited 0; no global bundle registry or live VM PID marker remained. A modified signed base manifest and the wrong PR identity were refused before launch on the existing cache. Focused transient-admission, composer, format, Clippy, size/trust-site gates and just check::gated passed.

    Keep this issue open: the guest-runtime quartet above was signed for an earlier commit on the same PR, not the exact current source; the current-head quartet job is still pending. No aarch64 CLI witness, full workspace tests, production base descriptor, v3 graph admission or release/publication claim is made. xtask check-rust-footprint remains red at 973,926 SLOC and 1,239,765 physical lines versus 966,000/1,232,000; this issue does not change that ratchet. The longer-term production boundary in the issue body remains the direction.

  3. auser commented on Nov 12, 2026

    @auser
    CollaboratorAuthor

    Follow-up product direction for the performance work (not implemented yet): install may download and prepare the verified image; start must perform fresh admission and meet the cold <300 ms / warm <50 ms launch targets when inputs are local. A start that downloads missing inputs must show progress rather than silently spending preparation time. run --compose may transparently prepare on a miss, with visible progress, to preserve the one-command option. Preparation may retain a bounded unactivated standby with no workload grants, secrets, or network authority; claim must bind its exact runtime, image and newly admitted plan before activation. Cached bytes and standby state remain data, never publisher trust or reused authorization.

    The earlier 34/27 s KVM witness used an unoptimized debug CLI; draft #5326 now builds its PR-only witness with the existing release-witness profile (8be6429f10). The optimized CLI job is still running. No release-speed or warm-start claim is made from the debug timing. Before wiring standby into the PR-only runtime, the runtime-proof/claim path needs a security review and a live measurement; warm_pool_size=0 is intentional today.

  4. auser commented on Nov 12, 2026

    @auser
    CollaboratorAuthor

    Optimized PR-only x86_64 KVM measurement at draft #5326 (8be6429f10, release-witness CLI, signed PR base from run 43119905868 and signed same-PR guest-runtime quartet from earlier run 43108383169): cold mvmctl run --compose 11.02 s wall / 9.83 s user CPU; authenticated cache-hit repeat 8.91 s wall / 7.92 s user CPU. Both returned the guest value and exited 0; neither installed a global bundle. Admission-to-plan.launched was ~0.81 s on both, so even optimized binaries miss the requested <300 ms cold launch target; this path has no warm claim and cannot claim <50 ms. The repeat wrote ~285 MiB, and syscall timing shows repeated 71 MiB archive verification plus invocation-private extraction/rechecks dominating preparation. This corrects the debug-profile 34/27 s witness but is not a performance fix.

    Owner-approved direction: install may prepare the verified image and bounded, unactivated authority-free standby; run --compose may transparently prepare with progress on a miss, then start must freshly admit and bind exact image/runtime before activation. Persistent prepared bytes cannot become publisher authorization. An immutable data-custody and PR-runtime warm-claim design needs security review before replacing the invocation-private path. No release-speed claim, production authority, or merge is asserted; the issue remains open. The bounded remote test directory was removed after stopping its owned processes.

  5. auser commented on Nov 12, 2026

    @auser
    CollaboratorAuthor

    Implementation boundary found for the approved install/preparation + unactivated standby direction (not yet implemented): TransientComposition::stage currently verifies and extracts into a per-invocation TempDir, while standby_boot::factory_parent_config deliberately refuses both PR-only runtime proof and kernel_read_sha256 local-kernel custody before warming. bundle_runtime::attach_cli_runtime sets warm_pool_size=0; the entrypoint boot path starts a cold backend directly. Simply retaining the extracted directory or removing those guards would turn mutable cached data into a warm-launch input without an independently checked lifetime/claim proof.

    The existing digest-cache sidecar is HMAC-bound to inode/ctime, but its own documentation says a process of the same user able to read the host key can mint a seal. ADR-001 includes a same-user hostile process, so that sidecar alone is not the immutable host artifact proof for a sub-50-ms fast path. A versioned prepared-data custody contract, explicit no-authority parent, runtime/kernel proof binding at warm claim, fresh policy/admission at start, and backend-specific immutable-byte witness must be reviewed before changing the refusals. No code or release guarantee is claimed by this note; #5326 still has only a cold Dev composition path.

  6. auser commented on Nov 12, 2026

    @auser
    CollaboratorAuthor

    Design review requested — proposed named-machine composition (not implemented or shipped)

    The owner rejected both mvmctl compose and a top-level install. The agreed UX is mvmctl machine create NAME --pack PACK.TOML, followed by mvmctl machine start NAME; machine rm NAME removes the definition. Keep mvmctl run --compose PACK.TOML as a one-shot convenience that visibly prepares on a miss. Do not overload --manifest: it currently means an image-backed mvm.toml/Mvmfile.toml source. Cover x86_64/aarch64 Firecracker and macOS/HVF with the same CLI contract.

    Authority boundary: create verifies the recipe and selected signed base/runtime/application inputs, records the source identity and exact prepared-data pins in a versioned machine definition, and may prepare a bounded standby. The definition and cache confer NO publisher enrollment, plan admission, or later-launch authorization. start verifies current trust, revocation/policy and exact held input identity; a changed recipe, stale proof, mismatched backend/architecture or missing immutable custody refuses or visibly re-prepares, never silently reuses cached authority. It creates a new, short-lived one-use Dev admission bound to the exact image/kernel/runtime, host/user, machine and plan, then claims only a matching standby after admission. The standby has no workload grants, secrets, volume, egress or mailbox authority; its claim cannot mint any. Repeated starts get new admission and a new claim, not a replay of the transient capability in the existing one-shot path. The ordinary enrolled-bundle registry and Prod/fleet path remain unchanged.

    State ownership: named definition -> verified prepared bytes -> authority-free standby -> reserved claim -> freshly admitted active machine. machine rm, TTL eviction, crash, signer change, revocation or policy drift invalidates matching standby; a cold rebuild must show progress. Cleanup/failed claims retain or quarantine uncertain VMs rather than hand them back as healthy. Prepared data can persist, but mutable cache metadata or an HMAC sidecar is not immutable custody against the same-user hostile process in ADR-001. Review must establish a backend-specific immutable-byte witness across the entire parent/child lifetime, including macOS/HVF and the PR-only guest runtime, before removing the current cold-only guards.

    Evidence required before a speed claim: parsing/spec migration and restart tests; tampered inputs, wrong principal, stale/revoked proof, replay, changed policy, wrong backend, quota exhaustion and failed cleanup; real guest-value and cache-hit witnesses on Firecracker x86_64/aarch64 and HVF; end-to-end cold <300 ms and warm <50 ms with fresh admission included, reported separately from download/preparation. Existing optimized PR-only Firecracker measurements were 11.02 s cold and 8.91 s repeat, and do not meet either target. No new code, SLO claim, production authority or merge is asserted by this review request.

    Requested review decision: approve the machine definition as data-only and the fresh-admission/standby claim boundary, including the backend-specific immutable custody proof, before wiring the named-machine path. This should not be implemented by storing a .mvmpkg in the installed registry or by deleting the cold-only refusals.

  7. auser commented on Nov 12, 2026

    @auser
    CollaboratorAuthor

    Cold and warm start design is owner-approved for Linux/Firecracker and macOS/HVF. Implementation is blocked on one concrete custody decision, not on CLI naming: the existing VerifiedRestoreFile source explicitly says its unlinked descriptor clone is NOT secure against another same-user process, because the temporary clone name can be opened for writing before unlink and the unsandboxed same-user supervisor retains host signer access (crates/mvm-vmm/src/host/restore_image.rs:29-45). ADR-001 includes that same-user process in the adversary model. The current signed/verified composition is restaged per invocation; the standby factory explicitly refuses both PR runtime proof and local kernel descriptor custody. A fast claim cannot safely replace a required full byte check with the digest sidecar or a mutable path.

    Recommendation for review: keep both cold and warm starts, with fresh admission on every start. Establish immutable byte custody for the entire standby/child lifetime: a sealed immutable object plus process identity on Linux, and an isolated separately owned/sandboxed custody service or equivalent OS-enforced immutable object on macOS. The backend must refuse fast claim when that proof is unavailable; a cold path can still reverify and boot. Do not claim <300 ms cold or <50 ms warm until a real backend witness includes admission and reaches guest readiness. This note does not implement or relax the existing guard.

  8. auser commented on Nov 12, 2026

    @auser
    CollaboratorAuthor

    Owner refinement for named-machine composition: both cold and warm starts are required on Linux/Firecracker and macOS/HVF. The stronger, OS-enforced immutable standby custody on macOS must be OPTIONAL and easy to enable; ordinary machine create NAME --pack PACK.TOML and machine start NAME must work without installing a privileged helper. Absence or failure of the optional custody service must not grant authority or misreport a cold boot as a warm claim. The command must explicitly report that warm acceleration is unavailable, then use the verified cold path; never skip current trust/admission to hide a latency miss. The cold <300 ms and warm <50 ms end-to-end targets, including admission, remain acceptance criteria and are not met by the current draft. This is an approved UX and capability requirement, not a claim that the all-platform implementation exists.

  9. auser commented on Nov 12, 2026

    @auser
    CollaboratorAuthor

    Implementation checkpoint on draft #5326 at c48a202 (pushed, not merged): verified composition-data preparation is split from invocation-private staging; MachineSpec can persist a data-only local recipe/archive identity without enrolling a publisher; recipe source pins re-check changed/symlinked input; image/registry/library start paths refuse that new source rather than silently booting something else. Focused runtime/client tests, scoped Clippy, formatting and just check::gated passed for the shared spec addition; the new recipe-pin test, formatting and scoped Clippy passed after the follow-up. The first recipe-pin test exposed macOS /tmp canonicalization and was corrected. No full workspace test or live all-platform witness is claimed.

    Still OPEN and not usable: machine create --pack is not exposed; no named cold start, per-start admission/resource ownership, optional HVF custody, warm claim or <300/<50 ms evidence exists. The existing transient entrypoint path explicitly refuses keep-alive for a private composition (mvm-client/src/entrypoint/call.rs), so simply clearing a CLI flag would not supply persistent custody; do not remove the refusal until the new owner and cleanup/stop path exists. Existing one-command Dev transient flow remains preview-only. No claim of release/publication/merge readiness.

  10. auser commented on Nov 12, 2026

    @auser
    CollaboratorAuthor

    Checkpoint on draft #5326: the named machine create NAME --pack PACK.TOML source and selected local signed-base/PR-runtime paths now persist as data only. machine start NAME re-verifies, freshly admits, retains private boot bytes and sends only the sealed entrypoint to a Dev guest. The flag remains hidden until a live named-machine witness and custody requirements pass. Focused source/CLI tests, just check::gated, fmt and actionlint passed; the footprint ratchet was raised with explicit owner approval and is now green at 977,274/977,500 SLOC and 1,243,740/1,244,000 physical lines after syncing current main.

    On x86_64 Hetzner KVM at 4d9e5d21ad, the same-head PR-only signed CLI/base/runtime artifacts from Actions run 43172747569 yielded COMPOSED_GUEST_VALUE=print('ready') from mvmctl run --compose on both cold (11.19 s wall) and authenticated-cache-hit repeat (8.52 s wall) launches. This verifies the one-shot flow only. A root-run trial refused Firecracker before boot as designed; a runuser trial lacked a systemd user bus; the direct non-root mvm-ops SSH session served the successful witnesses. No speed claim follows from these numbers.

    The PR-only aarch64 base-signing job initially failed because its actual arm64 kernel is an Image, not ELF. Commit e8b95b4e7b now checks ARMd at byte 56 and declares kernel:image; actionlint passes, fresh CI is pending. Named Firecracker guest output/restart/cleanup, aarch64 KVM and macOS/HVF guests, immutable optional warm custody and end-to-end <300/<50 ms with fresh admission remain unwitnessed. This issue stays open; no release artifact or production authority is claimed.

  11. auser commented on Nov 12, 2026

    @auser
    CollaboratorAuthor

    PR #5326 now has a live named-machine guest-output witness without publisher enrollment: at 4b95627, same-head PR-signed CLI/base/runtime from run 43284492364 on x86_64 KVM/Firecracker ran machine create packed-fixed --pack, start, logs, stop/restart and emitted COMPOSED_GUEST_VALUE=print('ready') on both starts. Create was 4.70 s, first start 11.03 s, authenticated cache-hit restart 8.77 s. A native macOS arm64 HVF test with PR-signed arm64 base/runtime likewise emitted COMPOSED_GUEST_VALUE=ready on first and repeat starts (9.74 s and 9.77 s; local CLI build). The guest /dev/console permission failure was fixed by retaining a write-only descriptor before UID 901 drop, without widening device access. This is not speed acceptance: cold <300 ms and warm <50 ms including admission remain unmet, safe warm custody is absent, arm64 Linux/KVM remains unwitnessed, and current-head CI is pending. PR stays draft; no release or images.lock advance.

  12. auser commented on Nov 14, 2026

    @auser
    CollaboratorAuthor

    Burn-down triage (2026-11-14): the implementation work for this decision continues under the composable-workloads program — #5416 (Bound composable Dev preview to one-use authority, governing epic #5415, architecture #5413), which explicitly preserves this issue and merged #5301. The draft composer #5326 is closed unmerged; #5301 enrollment gate is merged. No action taken here beyond recording the handoff; closing criteria here (real guest-value/cache-hit witness + required gates on main) remain owned by that program.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions