Skip to content

the per-machine lock's generator field is never refreshed — intel's receipt says forjar 0.1.0 for an apply run by 1.30.0 #580

Description

@noahgift

The per-machine lock's generator field is never refreshed — every apply receipt on this fleet names the wrong binary

Trying to answer "which forjar version produced this apply receipt?" retroactively, I found the only version field in a machine lock is the header's generator, and it is preserved from whenever the file was first created. Measured across paiml/infra's state dir, 2026-09-16:

lock generator: says generated_at: binary that ACTUALLY ran that apply (event log)
intel forjar 0.1.0 2026-09-16T02:11:15Z 1.30.0 (r-ab35e7e5f928)
gx10 forjar 1.13.1 2026-09-16T02:12:41Z 1.30.0 (r-ab49ff0c7517)
yoga forjar 1.1.1 2026-09-15T09:19:01Z 1.30.0 (r-73f8cc5cbc7d)
lambda-labs forjar 1.4.0 2026-09-14T16:47:03Z 1.30.0 (r-3da7029e1237)
mini forjar 1.6.1 2026-09-14T17:16:17Z 1.30.0 (r-3f0d731dbfb7)

Not one is right, and the errors span 0.1.0 to 1.13.1 — they look like the version each lock was first created at, years of releases ago.

Root cause. finalize_machine (src/core/executor/machine_b.rs:37) refreshes the timestamp and saves:

lock.generated_at = eventlog::now_iso8601();
if cfg.config.policy.lock_file {
    state::save_lock(cfg.state_dir, lock)?;
}

It never assigns lock.generator. The only non-test writer is src/core/state/stamp/mod.rs:340 (lock.generator.clone_from(&generator)), which is the GlobalLock stamp path, not the per-machine lock. So a machine lock is deserialized, its generated_at moved forward, and its original generator written straight back out.

Why it went unnoticed. src/cli/lock_audit.rs:98 is the check that looks at this field, and it asserts only lock.generator.starts_with("forjar"). forjar 0.1.0 passes. The audit for this field cannot fail on the thing that is wrong with it — a green that has no red.

Consequence. Apply provenance is unverifiable from the lock. forjar history --json does carry a correct per-event forjar_version, so the information exists; it just never reaches the receipt anyone reads. A fleet trying to audit "which applies ran under the old exit-code semantics, before the 1.31.0 pin" has to reconstruct it from the event log, and any lock older than its event-log retention cannot be stamped at all.

Suggested fix. Assign lock.generator = format!("forjar {}", env!("CARGO_PKG_VERSION")) in finalize_machine alongside generated_at, and tighten lock_audit to compare against the running version — reporting a mismatch as information (a lock written by an older forjar is normal and worth knowing), not as a failure.

Falsifier for the fix: take a lock whose generator is forjar 0.1.0, apply with the current binary, assert the header now names the current version. That test is red against today's tree.

Found while auditing paiml/infra's 1.31.0 pin. Related: #579 (apply/plan should refuse when the running binary does not match the manifest pin) — same theme, that forjar does not currently tie an apply to the binary that performed it.

Activity

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