internal/checks/supply_test.go
Rama main · réplica de lectura del repositorio original.
package checks
import (
"maps"
"strings"
"testing"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
const pinnedImage = "ghcr.io/sophotechlabs/api:1.4.2@sha256:" +
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
func sourcedContainer(fields map[string]any) map[string]any {
base := map[string]any{"image": pinnedImage}
maps.Copy(base, fields)
return container("app", base)
}
func labelledWorkload(kind, name string, spec map[string]any) *unstructured.Unstructured {
obj := workload(kind, name, spec)
meta, ok := obj.Object["metadata"].(map[string]any)
if ok {
meta["labels"] = map[string]any{nameLabel: name}
}
template, ok := specOf(obj)["template"].(map[string]any)
if ok {
template["metadata"] = map[string]any{"labels": map[string]any{"app": name}}
}
return obj
}
func sourced(spec map[string]any) *unstructured.Unstructured {
return labelledWorkload("Deployment", "api", spec)
}
func sourcedClean() *unstructured.Unstructured {
return sourced(podSpec(sourcedContainer(nil)))
}
func namespaced(obj *unstructured.Unstructured, namespace string) *unstructured.Unstructured {
meta, ok := obj.Object["metadata"].(map[string]any)
if ok {
meta["namespace"] = namespace
}
return obj
}
func TestEverySupplyCheckFiresOnItsOwnFaultAndOnNothingElse(t *testing.T) {
cases := []struct {
id string
trips *unstructured.Unstructured
}{
{
id: "image-not-digest-pinned",
trips: sourced(podSpec(sourcedContainer(map[string]any{"image": "ghcr.io/x/api:1.4.2"}))),
},
{
id: "image-from-docker-hub",
trips: sourced(podSpec(sourcedContainer(map[string]any{"image": "nginx:1.27"}))),
},
{
id: "pull-policy-not-always",
trips: sourced(podSpec(sourcedContainer(map[string]any{
"image": "ghcr.io/x/api:1.4.2",
"imagePullPolicy": "IfNotPresent",
}))),
},
{
id: "private-registry-no-pull-secret",
trips: sourced(podSpec(sourcedContainer(map[string]any{"image": "registry.sopho.tech/api:1.4.2"}))),
},
{
id: "secret-in-env-literal",
trips: sourced(podSpec(sourcedContainer(map[string]any{
"env": []any{map[string]any{"name": "DB_PASSWORD", "value": "hunter2"}},
}))),
},
{
id: "env-from-secret-wholesale",
trips: sourced(podSpec(sourcedContainer(map[string]any{
"envFrom": []any{map[string]any{"secretRef": map[string]any{"name": "api-secrets"}}},
}))),
},
{
id: "secret-volume-world-readable",
trips: sourced(podSpecWith(map[string]any{
"volumes": []any{map[string]any{
"name": "creds",
"secret": map[string]any{"secretName": "api", "defaultMode": int64(0o644)},
}},
}, sourcedContainer(nil))),
},
{
id: "default-namespace",
trips: namespaced(sourcedClean(), defaultNamespace),
},
{
id: "missing-recommended-labels",
trips: workload("Deployment", "api", podSpec(sourcedContainer(nil))),
},
{
id: "selector-template-mismatch",
trips: workload("Deployment", "api", podSpec(sourcedContainer(nil))),
},
{
id: "cpu-limit-set",
trips: sourced(podSpec(sourcedContainer(map[string]any{
"resources": map[string]any{"limits": map[string]any{cpuName: "500m"}},
}))),
},
}
registered := map[string]bool{}
for _, entry := range supplyChecks() {
registered[entry.id] = true
}
if len(cases) != len(registered) {
t.Fatalf("%d cases cover %d registered supply checks", len(cases), len(registered))
}
for _, tc := range cases {
t.Run(tc.id, func(t *testing.T) {
if !registered[tc.id] {
t.Fatalf("%s is not a registered supply check", tc.id)
}
if findingCount(t, report(t, tc.trips), tc.id) == 0 {
t.Fatalf("%s did not fire on the workload written to trip it", tc.id)
}
if findingCount(t, report(t, sourcedClean()), tc.id) != 0 {
t.Fatalf("%s fired on a workload with nothing wrong with it", tc.id)
}
})
}
}
func TestABareImageNameIsReadAsDockerHub(t *testing.T) {
found := report(t, sourced(podSpec(sourcedContainer(map[string]any{"image": "busybox:1.36"}))))
if findingCount(t, found, "image-from-docker-hub") != 1 {
t.Fatal("an image with no registry host was not read as Docker Hub")
}
}
func TestAHostWithNoDotIsAnOrganisationNotARegistry(t *testing.T) {
found := report(t, sourced(podSpec(sourcedContainer(map[string]any{"image": "library/nginx:1.27"}))))
if findingCount(t, found, "image-from-docker-hub") != 1 {
t.Fatal("an organization-qualified Docker Hub image was read as a private registry")
}
}
func TestALocalhostRegistryIsARegistry(t *testing.T) {
found := report(t, sourced(podSpec(sourcedContainer(map[string]any{"image": "localhost:5000/api:1.0"}))))
if findingCount(t, found, "image-from-docker-hub") != 0 {
t.Fatal("a localhost registry was read as Docker Hub")
}
if findingCount(t, found, "private-registry-no-pull-secret") != 1 {
t.Fatal("a localhost registry was treated as public")
}
}
func TestADigestPinnedImageIsNotAskedToPullAlways(t *testing.T) {
found := report(t, sourced(podSpec(sourcedContainer(map[string]any{
"imagePullPolicy": "IfNotPresent",
}))))
if findingCount(t, found, "pull-policy-not-always") != 0 {
t.Fatal("a digest-pinned image was asked to pull always")
}
}
func TestTheLatestTagIsLeftToItsOwnCheck(t *testing.T) {
found := report(t, sourced(podSpec(sourcedContainer(map[string]any{
"image": "ghcr.io/x/api:latest",
"imagePullPolicy": "IfNotPresent",
}))))
if findingCount(t, found, "pull-policy-not-always") != 0 {
t.Fatal(":latest was reported by the pull-policy check as well as its own")
}
if findingCount(t, found, "image-latest") != 1 {
t.Fatal("the latest-tag check stopped reporting it")
}
}
func TestAPullSecretSatisfiesThePrivateRegistryCheck(t *testing.T) {
found := report(t, sourced(podSpecWith(map[string]any{
"imagePullSecrets": []any{map[string]any{"name": "registry"}},
}, sourcedContainer(map[string]any{"image": "registry.sopho.tech/api:1.4.2"}))))
if findingCount(t, found, "private-registry-no-pull-secret") != 0 {
t.Fatal("a workload with imagePullSecrets was still reported")
}
}
func TestOnlyCredentialShapedNamesWithLiteralValuesAreReported(t *testing.T) {
fromSecret := report(t, sourced(podSpec(sourcedContainer(map[string]any{
"env": []any{map[string]any{
"name": "DB_PASSWORD",
"valueFrom": map[string]any{"secretKeyRef": map[string]any{"name": "db", "key": "password"}},
}},
}))))
if findingCount(t, fromSecret, "secret-in-env-literal") != 0 {
t.Fatal("a password read from a Secret was reported as a literal")
}
ordinary := report(t, sourced(podSpec(sourcedContainer(map[string]any{
"env": []any{map[string]any{"name": "LOG_LEVEL", "value": "debug"}},
}))))
if findingCount(t, ordinary, "secret-in-env-literal") != 0 {
t.Fatal("an ordinary environment variable was read as a credential")
}
named := report(t, sourced(podSpec(sourcedContainer(map[string]any{
"env": []any{map[string]any{"name": "STRIPE_API_KEY", "value": "sk_live_abcdef"}},
}))))
if !strings.Contains(onlyFinding(t, named, "secret-in-env-literal").Detail, "STRIPE_API_KEY") {
t.Fatal("a credential-shaped name with a literal value was not reported")
}
}
func TestAnEmptyCredentialValueIsNotReported(t *testing.T) {
found := report(t, sourced(podSpec(sourcedContainer(map[string]any{
"env": []any{map[string]any{"name": "API_TOKEN", "value": ""}},
}))))
if findingCount(t, found, "secret-in-env-literal") != 0 {
t.Fatal("an empty placeholder was reported as a credential")
}
}
func TestAConfigMapLoadedWholesaleIsNotASecretFinding(t *testing.T) {
found := report(t, sourced(podSpec(sourcedContainer(map[string]any{
"envFrom": []any{map[string]any{"configMapRef": map[string]any{"name": "settings"}}},
}))))
if findingCount(t, found, "env-from-secret-wholesale") != 0 {
t.Fatal("a ConfigMap loaded wholesale was reported as a Secret")
}
}
func TestATightSecretModeIsAccepted(t *testing.T) {
found := report(t, sourced(podSpecWith(map[string]any{
"volumes": []any{map[string]any{
"name": "creds",
"secret": map[string]any{"secretName": "api", "defaultMode": int64(0o400)},
}},
}, sourcedContainer(nil))))
if findingCount(t, found, "secret-volume-world-readable") != 0 {
t.Fatal("a secret volume at 0400 was reported")
}
}
func TestASecretVolumeThatSetsNoModeIsLeftAlone(t *testing.T) {
found := report(t, sourced(podSpecWith(map[string]any{
"volumes": []any{map[string]any{"name": "creds", "secret": map[string]any{"secretName": "api"}}},
}, sourcedContainer(nil))))
if findingCount(t, found, "secret-volume-world-readable") != 0 {
t.Fatal("a secret volume with no explicit mode was reported")
}
}
func TestASelectorLabelCarriedWithADifferentValueIsAMismatch(t *testing.T) {
obj := sourcedClean()
template, ok := specOf(obj)["template"].(map[string]any)
if !ok {
t.Fatal("the fixture has no pod template")
}
template["metadata"] = map[string]any{"labels": map[string]any{"app": "something-else"}}
if !strings.Contains(onlyFinding(t, report(t, obj), "selector-template-mismatch").Detail, "app") {
t.Fatal("a selector label carried with the wrong value was not reported")
}
}
func TestAWorkloadWithNoSelectorIsNotJudgedOnOne(t *testing.T) {
obj := sourcedClean()
delete(specOf(obj), "selector")
if findingCount(t, report(t, obj), "selector-template-mismatch") != 0 {
t.Fatal("a workload with no selector was reported as mismatched")
}
}
func TestAPodIsNotAskedAboutItsSelector(t *testing.T) {
found := report(t, pod("api", podSpec(sourcedContainer(nil))))
if findingCount(t, found, "selector-template-mismatch") != 0 {
t.Fatal("a bare pod was asked about a selector it cannot have")
}
}
func TestAlwaysPullSatisfiesAMutableTag(t *testing.T) {
obj := sourced(podSpec(sourcedContainer(map[string]any{
"image": "ghcr.io/acme/api:stable",
"imagePullPolicy": "Always",
})))
if findingCount(t, report(t, obj), "pull-policy-not-always") != 0 {
t.Fatal("Always was reported as an unsafe pull policy")
}
}
func TestASelectorWithMalformedMatchLabelsIsIgnored(t *testing.T) {
obj := sourcedClean()
specOf(obj)["selector"] = map[string]any{"matchLabels": "not-an-object"}
if findingCount(t, report(t, obj), "selector-template-mismatch") != 0 {
t.Fatal("malformed matchLabels were treated as a selector")
}
}
func TestListsAndFieldsOfTheWrongShapeAreSkippedByTheSupplyChecks(t *testing.T) {
obj := sourced(podSpecWith(map[string]any{
"volumes": []any{"not-an-object"},
"imagePullSecrets": []any{},
}, sourcedContainer(map[string]any{
"env": []any{"not-an-object"},
"envFrom": []any{"not-an-object"},
})))
specOf(obj)["selector"] = map[string]any{"matchLabels": map[string]any{"app": int64(7)}}
found := report(t, obj)
for _, id := range []string{
"secret-in-env-literal",
"env-from-secret-wholesale",
"secret-volume-world-readable",
"selector-template-mismatch",
} {
if findingCount(t, found, id) != 0 {
t.Fatalf("%s reported something from a field of the wrong shape", id)
}
}
}
func TestEveryBatchCheckFiresOnItsOwnFaultAndOnNothingElse(t *testing.T) {
settledJob := func() *unstructured.Unstructured {
obj := labelledWorkload("Job", "import", podSpecWith(map[string]any{
"restartPolicy": "Never",
}, sourcedContainer(nil)))
spec := specOf(obj)
spec[ttlField] = int64(3600)
spec[activeDeadline] = int64(600)
spec[backoffField] = int64(4)
return obj
}
settledCron := func() *unstructured.Unstructured {
obj := cronJob("nightly", podSpecWith(map[string]any{
"restartPolicy": "OnFailure",
}, sourcedContainer(nil)))
spec := specOf(obj)
spec[startingDeadline] = int64(120)
spec[concurrencyField] = "Forbid"
spec[successHistory] = int64(3)
spec[failedHistory] = int64(1)
template, hasTemplate := spec["jobTemplate"].(map[string]any)
if !hasTemplate {
t.Fatal("the fixture has no job template")
}
jobSpec, hasSpec := template[specField].(map[string]any)
if !hasSpec {
t.Fatal("the job template has no spec")
}
jobSpec[ttlField] = int64(3600)
jobSpec[activeDeadline] = int64(600)
return obj
}
cases := []struct {
id string
trips *unstructured.Unstructured
settle *unstructured.Unstructured
}{
{
id: "job-no-ttl",
trips: func() *unstructured.Unstructured {
obj := settledJob()
delete(specOf(obj), ttlField)
return obj
}(),
settle: settledJob(),
},
{
id: "job-no-active-deadline",
trips: func() *unstructured.Unstructured {
obj := settledJob()
delete(specOf(obj), activeDeadline)
return obj
}(),
settle: settledJob(),
},
{
id: "job-backoff-limit",
trips: func() *unstructured.Unstructured {
obj := settledJob()
specOf(obj)[backoffField] = int64(0)
return obj
}(),
settle: settledJob(),
},
{
id: "cronjob-no-starting-deadline",
trips: func() *unstructured.Unstructured {
obj := settledCron()
delete(specOf(obj), startingDeadline)
return obj
}(),
settle: settledCron(),
},
{
id: "cronjob-concurrency-allow",
trips: func() *unstructured.Unstructured {
obj := settledCron()
specOf(obj)[concurrencyField] = allowConcurrent
return obj
}(),
settle: settledCron(),
},
{
id: "cronjob-unbounded-history",
trips: func() *unstructured.Unstructured {
obj := settledCron()
delete(specOf(obj), successHistory)
return obj
}(),
settle: settledCron(),
},
}
registered := map[string]bool{}
for _, entry := range batchChecks() {
registered[entry.id] = true
}
if len(cases) != len(registered) {
t.Fatalf("%d cases cover %d registered batch checks", len(cases), len(registered))
}
for _, tc := range cases {
t.Run(tc.id, func(t *testing.T) {
if findingCount(t, report(t, tc.trips), tc.id) == 0 {
t.Fatalf("%s did not fire on the object written to trip it", tc.id)
}
if findingCount(t, report(t, tc.settle), tc.id) != 0 {
t.Fatalf("%s fired on a settled %s", tc.id, tc.settle.GetKind())
}
})
}
}
func TestACronJobIsJudgedOnItsJobTemplate(t *testing.T) {
obj := cronJob("nightly", podSpec(sourcedContainer(nil)))
found := report(t, obj)
if findingCount(t, found, "job-no-ttl") != 1 {
t.Fatal("a CronJob's job template was not read for its ttl")
}
patch := onlyFinding(t, found, "job-no-ttl").Patch
if !strings.Contains(patch, "jobTemplate") {
t.Fatalf("the patch was rooted at the wrong place:\n%s", patch)
}
}
func TestADeploymentIsNotAskedAboutJobFields(t *testing.T) {
found := report(t, sourcedClean())
for _, id := range []string{"job-no-ttl", "job-no-active-deadline", "cronjob-concurrency-allow"} {
if findingCount(t, found, id) != 0 {
t.Fatalf("%s was asked of a Deployment", id)
}
}
}
func TestAHighBackoffLimitIsReportedAndAModerateOneIsNot(t *testing.T) {
high := labelledWorkload("Job", "import", podSpecWith(map[string]any{"restartPolicy": "Never"},
sourcedContainer(nil)))
specOf(high)[backoffField] = int64(500)
if !strings.Contains(onlyFinding(t, report(t, high), "job-backoff-limit").Detail, "500") {
t.Fatal("a high backoffLimit was not reported")
}
moderate := labelledWorkload("Job", "import", podSpecWith(map[string]any{"restartPolicy": "Never"},
sourcedContainer(nil)))
specOf(moderate)[backoffField] = int64(6)
if findingCount(t, report(t, moderate), "job-backoff-limit") != 0 {
t.Fatal("a backoffLimit of 6 was reported")
}
}
func TestTheCronHistoryCheckNamesWhichLimitIsWrong(t *testing.T) {
obj := cronJob("nightly", podSpec(sourcedContainer(nil)))
specOf(obj)[successHistory] = int64(50)
if !strings.Contains(onlyFinding(t, report(t, obj), "cronjob-unbounded-history").Detail, successHistory) {
t.Fatal("the history finding did not name the limit that is wrong")
}
}