package signedjobs import ( "context" "testing" "time" ) // TASK D1 Group B — the agent_update op class RIDES the same LOCKED gate pipeline as every other // destructive op. These tests use the REAL authz.Verifier + reconcile.Gate (via newRealGateRunner) // over genuinely-minted signed blobs, asserting agent_update is gated identically to storage_wipe. const agentUpdateParamsJSON = `{"version":"0.70.1","sha256":"` + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + `"}` // A correctly-signed agent_update by the PINNED operational key reaches the executor (a fake here; // the real executor is unit-tested in internal/selfupdate). Proves the class is authorized, not // silently dropped. func TestRunner_ValidSignedAgentUpdateExecutes(t *testing.T) { s := newTestSigner(t) r, src, exec := newRealGateRunner(t, s) now := time.Now().UTC() src.add(mintJobOp(t, s, "agent_update", "au1", testHost, "", "ops-1", agentUpdateParamsJSON, now, now.Add(time.Hour))) if _, err := r.RunOnce(context.Background()); err != nil { t.Fatalf("RunOnce: %v", err) } if exec.count() != 1 || exec.calls[0] != "agent_update" { t.Fatalf("executor calls = %v, want one agent_update", exec.calls) } if !src.wasCompleted("au1") { t.Error("valid agent_update job not cleared") } } // A NON-PINNED signer's agent_update is REJECTED — the executor is never called. This is the // companion to the class-allowlist question: agent_update is classified Destructive // (reconcile.Classify), so an unsigned/wrong-key op cannot reach the binary swap. If the class were // ever mis-classified Benign, this signature check would be bypassed and the test would fail. func TestRunner_NonPinnedAgentUpdateRejected(t *testing.T) { pinned := newTestSigner(t) attacker := newTestSigner(t) // not pinned r, src, exec := newRealGateRunner(t, pinned) now := time.Now().UTC() src.add(mintJobOp(t, attacker, "agent_update", "au1", testHost, "", "ops-1", agentUpdateParamsJSON, now, now.Add(time.Hour))) r.RunOnce(context.Background()) if exec.count() != 0 { t.Errorf("a non-pinned agent_update was EXECUTED (count=%d) — the binary swap must be gated", exec.count()) } if !src.wasCompleted("au1") { t.Error("rejected agent_update job should be cleared") } } // An agent_update targeting ANOTHER host is rejected on this host (anti-retarget) — an operator // can't accidentally push a build to the wrong box. func TestRunner_AgentUpdateRetargetRejected(t *testing.T) { s := newTestSigner(t) r, src, exec := newRealGateRunner(t, s) now := time.Now().UTC() src.add(mintJobOp(t, s, "agent_update", "au1", "some-other-host", "", "ops-1", agentUpdateParamsJSON, now, now.Add(time.Hour))) r.RunOnce(context.Background()) if exec.count() != 0 { t.Errorf("an agent_update for another host was executed here (count=%d)", exec.count()) } }