From 9798a2b5fe2fba3d3458f55071624c7962b0ae77 Mon Sep 17 00:00:00 2001 From: Steve Cliff Date: Fri, 1 May 2026 18:24:56 +0100 Subject: [PATCH] agent: log accept/complete on backup jobs; audit: populate host.enrolled payload MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two warts surfaced during the smoke run: - Agent was silent between "config.update applied" and "job finished" — operators tailing journalctl saw no acknowledgement that a command.run had landed. Adds Info logs at job-accept ({job_id, paths}) and at successful completion. - The host.enrolled audit row had an empty {} payload. Now carries {hostname, os, arch, has_repo_creds} so an audit-log reader can answer "what got enrolled and did the operator bundle creds with the token" without joining back to hosts. Co-Authored-By: Claude Opus 4.7 (1M context) --- cmd/agent/main.go | 4 ++++ internal/server/http/enrollment.go | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/cmd/agent/main.go b/cmd/agent/main.go index b970f7a..2e9b71d 100644 --- a/cmd/agent/main.go +++ b/cmd/agent/main.go @@ -250,10 +250,14 @@ func (d *dispatcher) runJob(ctx context.Context, p api.CommandRunPayload, tx wsc case api.JobBackup: // Agent.Args carries [paths...]. Excludes/tags are not yet // surfaced over the wire; they come with P2 schedule support. + slog.Info("agent: accepting backup job", + "job_id", p.JobID, "paths", p.Args) go func() { if err := r.RunBackup(ctx, p.JobID, p.Args, nil, nil); err != nil { slog.Warn("agent: backup job failed", "job_id", p.JobID, "err", err) + return } + slog.Info("agent: backup job complete", "job_id", p.JobID) }() default: return fmt.Errorf("kind %q not implemented yet (Phase 2 lands the rest)", p.Kind) diff --git a/internal/server/http/enrollment.go b/internal/server/http/enrollment.go index 0998565..05e0505 100644 --- a/internal/server/http/enrollment.go +++ b/internal/server/http/enrollment.go @@ -146,6 +146,17 @@ func (s *Server) handleAgentEnroll(w stdhttp.ResponseWriter, r *stdhttp.Request) } } + auditPayload, _ := json.Marshal(struct { + Hostname string `json:"hostname"` + OS string `json:"os"` + Arch string `json:"arch"` + HasRepoCreds bool `json:"has_repo_creds"` + }{ + Hostname: host.Name, + OS: host.OS, + Arch: host.Arch, + HasRepoCreds: encForHost != "", + }) _ = s.deps.Store.AppendAudit(r.Context(), store.AuditEntry{ ID: ulid.Make().String(), Actor: "system", @@ -153,6 +164,7 @@ func (s *Server) handleAgentEnroll(w stdhttp.ResponseWriter, r *stdhttp.Request) TargetKind: ptr("host"), TargetID: &hostID, TS: host.EnrolledAt, + Payload: auditPayload, }) writeJSON(w, stdhttp.StatusCreated, enrollResponse{