package osupdate import ( "context" "encoding/base64" "encoding/json" "errors" "testing" "gitea.dooplex.hu/admin/felhom-agent/internal/hub" "gitea.dooplex.hu/admin/felhom-agent/internal/reconcile" "gitea.dooplex.hu/admin/felhom-agent/internal/signedjobs" ) // The executor hands the RAW signed bytes to the wrapper (which verifies them itself) and the exact signed package // list. Red-proof: drop the `signed` field from the docker plan in runLayer and the plan check fails. func TestDockerStepExecutor_PassesTheSignedEnvelope(t *testing.T) { w := &fakeWrapper{t: t, applyRep: map[string]WrapperReport{LayerDocker: { Upgraded: []Package{{Name: "docker-ce", Version: "5:29.8.2-1~debian.13~trixie"}}, DockerEngine: "29.8.2", Authority: "signed"}}} l, h := newLeg(t, w, &hub.WireOSUpdate{Ring: 1, Enabled: true}) e := DockerStepExecutor{Leg: l, Guest: func(context.Context) (int, error) { return 9201, nil }} params, _ := json.Marshal(DockerStepParams{ReleaseID: "os-docker-1", Packages: []Package{{Name: "docker-ce", Version: "5:29.8.2-1~debian.13~trixie", Origin: "Docker CE"}}}) ctx := signedjobs.WithSignedOp(context.Background(), &reconcile.SignedOp{Blob: []byte(`{"op":"os_docker_step"}`), Sig: []byte("SIG")}) if err := e.Execute(ctx, OpDockerStep, params); err != nil { t.Fatal(err) } dp := w.plans[len(w.plans)-1] sg, _ := dp["signed"].(map[string]any) if dp["layer"] != "docker" || dp["lane"] != "slow" || dp["release_id"] != "os-docker-1" || sg == nil || sg["blob_b64"] != base64.StdEncoding.EncodeToString([]byte(`{"op":"os_docker_step"}`)) || sg["sig"] != "SIG" { t.Fatalf("docker plan = %v", dp) } if calls(w) != "guest:live-restore-on,docker:apply" || len(h.reports) != 1 || h.reports[0].Trigger != "signed" { t.Fatalf("calls=%s reports=%+v", calls(w), h.reports) } } func TestDockerStepExecutor_RefusesWithoutEnvelopeAndPassesOtherOps(t *testing.T) { w := &fakeWrapper{t: t} l, _ := newLeg(t, w, &hub.WireOSUpdate{Ring: 1, Enabled: true}) e := DockerStepExecutor{Leg: l, Guest: func(context.Context) (int, error) { return 9201, nil }} if err := e.Execute(context.Background(), "agent_update", nil); !errors.Is(err, signedjobs.ErrNoExecutor) { t.Fatalf("another op must pass through the chain: %v", err) } params, _ := json.Marshal(DockerStepParams{Packages: []Package{{Name: "docker-ce", Version: "1"}}}) if err := e.Execute(context.Background(), OpDockerStep, params); err == nil || len(w.plans) != 0 { t.Fatalf("no envelope must refuse before any wrapper call: err=%v calls=%s", err, calls(w)) } }