package enroll import ( "fmt" "os" "path/filepath" "testing" ) func TestLoadAcceptsValidEnrollmentAndRendersPinnedUnit(t *testing.T) { set, err := Load(enrollmentFile(t, "[Container]\nImage=${image}\n", `"deadline": "10m", "stableFor": "1m", "restartBudget": 2`)) if err != nil { t.Fatal(err) } service, ok := set.Lookup("app") if !ok { t.Fatal("service app missing") } reference := service.Reference("sha256:0000000000000000000000000000000000000000000000000000000000000000") if unit := service.RenderUnit(reference); unit != "[Container]\nImage="+reference+"\n" { t.Fatalf("unit = %q", unit) } if service.UnitFileName() != "app.container" || service.UnitName() != "app.service" { t.Fatalf("unit names = %s %s", service.UnitFileName(), service.UnitName()) } if service.Probation.DeadlineDuration().Minutes() != 10 || service.Probation.StableForDuration().Minutes() != 1 { t.Fatalf("probation = %+v", service.Probation) } } func TestEmptyEnrollmentStartsWithNoCapabilities(t *testing.T) { path := filepath.Join(t.TempDir(), "enrollment.json") if err := os.WriteFile(path, []byte("[]\n"), 0o600); err != nil { t.Fatal(err) } set, err := Load(path) if err != nil { t.Fatal(err) } if names := set.Names(); len(names) != 0 { t.Fatalf("names = %v", names) } } func TestLoadRejectsUnsafeEnrollment(t *testing.T) { cases := map[string]struct { template string probation string }{ "auto update": {"[Container]\nImage=${image}\nAutoUpdate=registry\n", `"deadline": "10m", "stableFor": "1m", "restartBudget": 1`}, "no image placeholder": {"[Container]\nImage=registry.invalid/app:latest\n", `"deadline": "10m", "stableFor": "1m", "restartBudget": 1`}, "window exceeds deadline": {"[Container]\nImage=${image}\n", `"deadline": "1m", "stableFor": "10m", "restartBudget": 1`}, "negative budget": {"[Container]\nImage=${image}\n", `"deadline": "10m", "stableFor": "1m", "restartBudget": -1`}, "unparsable deadline": {"[Container]\nImage=${image}\n", `"deadline": "soon", "stableFor": "1m", "restartBudget": 1`}, } for name, test := range cases { if _, err := Load(enrollmentFile(t, test.template, test.probation)); err == nil { t.Fatalf("%s accepted", name) } } } func TestValidDigestRequiresPinnedManifestDigest(t *testing.T) { valid := "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" for _, digest := range []string{valid} { if !ValidDigest(digest) { t.Fatalf("rejected %q", digest) } } for _, digest := range []string{"", "latest", "sha256:XYZ", "sha512:" + valid[7:], valid + "0"} { if ValidDigest(digest) { t.Fatalf("accepted %q", digest) } } } func enrollmentFile(t *testing.T, template, probation string) string { t.Helper() root := t.TempDir() templatePath := filepath.Join(root, "app.container.template") enrollmentPath := filepath.Join(root, "enrollment.json") if err := os.WriteFile(templatePath, []byte(template), 0o600); err != nil { t.Fatal(err) } document := fmt.Sprintf(`[{ "name": "app", "unit": "app", "imageRepository": "registry.invalid/app", "unitTemplateFile": %q, "containerName": "app", "readinessURL": "http://127.0.0.1:9/ready", "probation": {%s} }]`, templatePath, probation) if err := os.WriteFile(enrollmentPath, []byte(document), 0o600); err != nil { t.Fatal(err) } return enrollmentPath }