Ctrl K
ComunidadGuías…

dockerfiles_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package main

import (
	"os"
	"regexp"
	"strings"
	"testing"
)

// dockerfilePaths are the two shipped image definitions. Both are read as plain
// text: the contract under test (digest pins, lockstep, healthcheck, labels) is
// entirely in the FROM/HEALTHCHECK/LABEL lines, so no Dockerfile parser is
// needed - and a parser would only add a dependency that could disagree with
// what BuildKit reads.
var dockerfilePaths = []string{"Dockerfile", "Dockerfile.iperf"}

var fromLineRe = regexp.MustCompile(`(?m)^FROM\s+(?:--platform=\S+\s+)?(\S+)`)

// pinnedRefRe is a full image ref pinned by digest: name[:tag]@sha256:<64 hex>.
var pinnedRefRe = regexp.MustCompile(`^[^@\s]+@sha256:[0-9a-f]{64}$`)

// TestDockerfilesEveryFromIsDigestPinned fails if any FROM line in either
// Dockerfile references a base by floating tag alone. A digest is the only
// immutable reference; a bare tag would silently change the base under a
// rebuild, which is exactly what the pins exist to prevent.
func TestDockerfilesEveryFromIsDigestPinned(t *testing.T) {
	for _, path := range dockerfilePaths {
		data, err := os.ReadFile(path)
		if err != nil {
			t.Fatalf("read %s: %v", path, err)
		}
		froms := fromLineRe.FindAllStringSubmatch(string(data), -1)
		if len(froms) == 0 {
			t.Fatalf("%s: no FROM lines found - the test's line matching has rotted", path)
		}
		for _, m := range froms {
			if !pinnedRefRe.MatchString(m[1]) {
				t.Errorf("%s: FROM %q is not digest-pinned (want name[:tag]@sha256:<64 hex>)", path, m[1])
			}
		}
	}
}

// TestDockerfilesDebianDigestsLockstep fails if the debian:13-slim digest
// drifts between ANY of its occurrences (one in Dockerfile, two in
// Dockerfile.iperf). The two images must build from the same base rebuild:
// half-bumped pins mean the setcap stage and the iperf final stage - or the
// two published images - carry different base layers, and nothing else in the
// build would ever report that.
func TestDockerfilesDebianDigestsLockstep(t *testing.T) {
	type pin struct {
		path   string
		digest string
	}
	var debianPins []pin
	for _, path := range dockerfilePaths {
		data, err := os.ReadFile(path)
		if err != nil {
			t.Fatalf("read %s: %v", path, err)
		}
		for _, m := range fromLineRe.FindAllStringSubmatch(string(data), -1) {
			name, digest, ok := strings.Cut(m[1], "@")
			if !ok {
				continue // the pinned-FROM test reports unpinned refs
			}
			if name == "debian:13-slim" {
				debianPins = append(debianPins, pin{path, digest})
			}
		}
	}
	// One in Dockerfile (setcap stage), two in Dockerfile.iperf (setcap + final).
	// Fewer means a base was renamed or dropped and this lockstep check went
	// vacuous - fail so the test is updated alongside that change, not skipped.
	if len(debianPins) != 3 {
		t.Fatalf("found %d debian:13-slim FROM pins across %v, want 3: %+v", len(debianPins), dockerfilePaths, debianPins)
	}
	first := debianPins[0]
	for _, p := range debianPins[1:] {
		if p.digest != first.digest {
			t.Errorf("debian:13-slim digest drift: %s has %s but %s has %s - bump every pin in the same change",
				first.path, first.digest, p.path, p.digest)
		}
	}
}

// TestDockerfilesHealthcheckAndAttribution pins the shipped-image metadata both
// Dockerfiles must carry: an exec-form HEALTHCHECK on the healthz subcommand
// (the string form needs a shell, which distroless does not have), and the
// static OCI attribution labels. Substring checks against the raw text keep
// this in step with what BuildKit actually reads.
func TestDockerfilesHealthcheckAndAttribution(t *testing.T) {
	required := []string{
		`CMD ["/pingularity", "healthz"]`,
		`org.opencontainers.image.source="https://github.com/pingular/pingularity"`,
		`org.opencontainers.image.licenses="MIT"`,
		`org.opencontainers.image.title=`,
		`org.opencontainers.image.description=`,
	}
	for _, path := range dockerfilePaths {
		data, err := os.ReadFile(path)
		if err != nil {
			t.Fatalf("read %s: %v", path, err)
		}
		text := string(data)
		if !strings.Contains(text, "HEALTHCHECK") {
			t.Errorf("%s: no HEALTHCHECK instruction", path)
		}
		for _, want := range required {
			if !strings.Contains(text, want) {
				t.Errorf("%s: missing %q", path, want)
			}
		}
	}
	// The iperf image must not start in / (unwritable for uid 65532); the
	// distroless base of the default image provides /home/nonroot on its own.
	iperf, err := os.ReadFile("Dockerfile.iperf")
	if err != nil {
		t.Fatalf("read Dockerfile.iperf: %v", err)
	}
	if !strings.Contains(string(iperf), "WORKDIR /var/lib/pingularity") {
		t.Error("Dockerfile.iperf: missing WORKDIR /var/lib/pingularity (process would start in unwritable /)")
	}
}

// The data directory has to ship at 0700, and the only way to get that in a
// distroless stage is to seed it one level down and copy it as an ENTRY: a
// directory COPY creates as its own destination is 0755 and --chmod never
// reaches it. The image shipped world-readable for a release because nothing
// static checked this - the only guard was a Docker-dependent CI leg.
func TestDockerfileShipsTheDataDirAt0700(t *testing.T) {
	b, err := os.ReadFile("Dockerfile")
	if err != nil {
		t.Fatalf("read Dockerfile: %v", err)
	}
	d := string(b)
	if !strings.Contains(d, "chmod 0700 /seed/pingularity") {
		t.Error("Dockerfile: the seeded data dir is not made 0700 in the builder stage")
	}
	if !strings.Contains(d, "COPY --from=setcap --chown=65532:65532 --chmod=0700 /seed/ /var/lib/") {
		t.Error("Dockerfile: data dir must be copied as an entry inside /seed, not as the COPY destination")
	}
	if strings.Contains(d, "/data /var/lib/pingularity") {
		t.Error("Dockerfile: copying onto /var/lib/pingularity makes it the destination, which ships 0755")
	}
}