Files
pulse/internal/agentexec/docker_observation_codec_test.go
2026-08-27 20:43:54 +01:00

95 lines
3.8 KiB
Go

package agentexec
import (
"encoding/json"
"strings"
"testing"
"time"
)
func TestDockerContainerObservationContractBindsRequestAndFreshResult(t *testing.T) {
now := time.Now().UTC()
req := DockerContainerObservationPayload{
RequestID: "observe-1", ActionID: "action-1", Runtime: "docker", ContainerID: strings.Repeat("a", 64),
}
if err := BindDockerContainerObservationPayload(&req); err != nil {
t.Fatal(err)
}
encoded, err := json.Marshal(req)
if err != nil {
t.Fatal(err)
}
decoded, err := DecodeDockerContainerObservationPayload(encoded)
if err != nil {
t.Fatal(err)
}
result := DockerContainerObservationResultPayload{
RequestID: decoded.RequestID, ActionID: decoded.ActionID, ProtocolVersion: decoded.ProtocolVersion, RequestDigest: decoded.RequestDigest,
Observed: true,
Snapshot: DockerContainerObservationSnapshot{ContainerID: decoded.ContainerID, State: "running", Running: true, Health: DockerContainerHealthHealthy, ObservedAt: now},
}
if err := ValidateDockerContainerObservationResultForRequest(decoded, result, now); err != nil {
t.Fatalf("fresh bound result rejected: %v", err)
}
tampered := result
tampered.ActionID = "different-action"
if err := ValidateDockerContainerObservationResultForRequest(decoded, tampered, now); err == nil {
t.Fatal("cross-action observation result was accepted")
}
stale := result
stale.Snapshot.ObservedAt = now.Add(-16 * time.Minute)
if err := ValidateDockerContainerObservationResultForRequest(decoded, stale, now); err == nil {
t.Fatal("stale observation result was accepted")
}
}
func TestDockerContainerObservationRequiresExplicitHealthTruth(t *testing.T) {
now := time.Now().UTC()
req := DockerContainerObservationPayload{RequestID: "observe-1", ActionID: "action-1", Runtime: "docker", ContainerID: strings.Repeat("a", 64)}
if err := BindDockerContainerObservationPayload(&req); err != nil {
t.Fatal(err)
}
base := DockerContainerObservationResultPayload{
RequestID: req.RequestID, ActionID: req.ActionID, ProtocolVersion: req.ProtocolVersion, RequestDigest: req.RequestDigest, Observed: true,
Snapshot: DockerContainerObservationSnapshot{ContainerID: req.ContainerID, State: "running", Running: true, ObservedAt: now},
}
for _, health := range []string{"", "unknown", "degraded"} {
result := base
result.Snapshot.Health = health
if err := ValidateDockerContainerObservationResultForRequest(req, result, now); err == nil {
t.Fatalf("health %q was accepted without canonical truth", health)
}
}
for _, health := range []string{DockerContainerHealthNone, DockerContainerHealthStarting, DockerContainerHealthHealthy, DockerContainerHealthUnhealthy} {
result := base
result.Snapshot.Health = health
if err := ValidateDockerContainerObservationResultForRequest(req, result, now); err != nil {
t.Fatalf("canonical health %q was rejected: %v", health, err)
}
}
}
func TestDockerContainerObservationWireCarriesFactsNotActionTruth(t *testing.T) {
payload, err := json.Marshal(DockerContainerObservationResultPayload{Snapshot: DockerContainerObservationSnapshot{Health: DockerContainerHealthHealthy}})
if err != nil {
t.Fatal(err)
}
encoded := string(payload)
for _, forbidden := range []string{`"success"`, `"verification"`, `"evidence"`, `"independent"`, `"command"`, `"operation"`, `"approval"`} {
if strings.Contains(encoded, forbidden) {
t.Fatalf("observation wire contains forbidden action-truth or authority field %s: %s", forbidden, encoded)
}
}
if !strings.Contains(encoded, `"health":"healthy"`) {
t.Fatalf("observation wire omitted explicit health fact: %s", encoded)
}
lifecycle, err := json.Marshal(DockerContainerLifecycleSnapshot{Health: DockerContainerHealthHealthy})
if err != nil {
t.Fatal(err)
}
if strings.Contains(string(lifecycle), `"health"`) {
t.Fatalf("version-1 lifecycle receipt wire changed incompatibly: %s", lifecycle)
}
}