feat: D1 Part 2 — agent self-update Go plumbing (op class, opsign, executor, commit, report)
- reconcile: ClassAgentUpdate op class; always Destructive (no provenance
blesses replacing the root-adjacent binary). classify test + companion
(TestClassify_AgentUpdateAlwaysDestructive).
- opsign: `-op agent_update` with -agent-version + -sha256 (isHex64-validated);
params {version,sha256}. isHex64 test (Group D).
- config: SelfUpdateConfig{URLTemplate,Username,Token,StateDir,DwellSeconds}
+ WithDefaults + Token redaction.
- internal/selfupdate: Executor (download → verify vs the SIGNED sha → sudo -n
wrapper `apply`; sha is the only integrity root — mismatch refuses + removes,
agent untouched); Manager (startup dwell → `commit`; version-mismatch → no
commit + loud WARN + marker left for report visibility; shutdown-before-dwell
leaves pending). WrapperRunner seam → tests never shell out.
- hub report: additive selfupdate_pending(+version) via SetSelfUpdateReporter
seam; both omitempty (Wireguard precedent) so the cross-repo golden contract
stays byte-stable — no hub change.
- capability manifest: 3 non-critical FELHOM_SELFUPDATE probes.
- main.go: updateExec appended to the executor chain; commit-manager wired to
the report seam + MaybeCommit goroutine after core init.
Tests: Group A (executor happy/sha-mismatch+companion/bad-params/wrapper-fail),
B (agent_update rides the real gate: pinned-key executes, non-pinned +
retarget rejected), C (commit/version-mismatch/no-pending/shutdown), D (opsign).
C2 companion red-proof verified (neutered Go verify → bad binary reaches apply
→ test fails), reverted. Full go test ./... green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
@@ -86,8 +86,13 @@ func (s testSigner) allowed(t *testing.T, keyID string, role authz.KeyRole) auth
|
||||
|
||||
// mintJob builds a hub.JobWire carrying a signed storage_wipe envelope from the given signer.
|
||||
func mintJob(t *testing.T, s testSigner, jobID, host, guest, keyID, paramsJSON string, issued, expires time.Time) hub.JobWire {
|
||||
return mintJobOp(t, s, "storage_wipe", jobID, host, guest, keyID, paramsJSON, issued, expires)
|
||||
}
|
||||
|
||||
// mintJobOp is mintJob with an explicit op class (for non-wipe ops, e.g. agent_update ride-along).
|
||||
func mintJobOp(t *testing.T, s testSigner, op, jobID, host, guest, keyID, paramsJSON string, issued, expires time.Time) hub.JobWire {
|
||||
t.Helper()
|
||||
blob, err := authz.CanonicalBlob("storage_wipe", host, guest, keyID, randNonce(), paramsJSON, issued, expires)
|
||||
blob, err := authz.CanonicalBlob(op, host, guest, keyID, randNonce(), paramsJSON, issued, expires)
|
||||
if err != nil {
|
||||
t.Fatalf("CanonicalBlob: %v", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user