mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-25 21:20:00 +00:00
592a1e52f6
govulncheck on the pinned 1.26.8 toolchain reports twelve reachable standard library vulnerabilities in Pulse (net/http, crypto/tls, html/template, os, net/textproto), published on 2026-10-08 and fixed in Go 1.26.9. golang.org/x/net v0.58.0 carries further advisories fixed in v0.60.0. With 1.26.9 and x/net v0.60.0 the scan reports no affecting vulnerabilities under both govulncheck v1.1.4 and v1.7.0. Pulse's own govulncheck job last ran on 2026-10-05, so nothing flagged this. The private Enterprise build and test job notices it: once the scan finds reachable advisories it needs more than the 4 GiB CI VM holds, the guest kernel kills govulncheck, and the job is cancelled. That has failed every Enterprise pair check since 2026-10-08, including the first beta's. Move every release builder and local toolchain guard together, as 1.26.8 did, so no candidate artifact keeps an older compiler: go.mod, the builder image digests (index digest for 1.26.9-alpine), the release and dev scripts, the devcontainer, and the root pair diagnostic. Only x/net is raised in the module graph; go mod tidy is deliberately not run, so unrelated indirect requirements stay as they were. Contract-Neutral: Toolchain and indirect dependency patch update that clears reported advisories; no product or runtime contract changed.
77 lines
3.6 KiB
Go
77 lines
3.6 KiB
Go
package installtests
|
|
|
|
import (
|
|
"os"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestIntegrationContainersUseGovernedImmutableBases(t *testing.T) {
|
|
dockerfileBytes, err := os.ReadFile(repoFile("tests", "integration", "mock-github-server", "Dockerfile"))
|
|
if err != nil {
|
|
t.Fatalf("read mock GitHub Dockerfile: %v", err)
|
|
}
|
|
dockerfile := string(dockerfileBytes)
|
|
assertDigestPinnedDockerStage(t, dockerfile, `FROM golang:1.26.9-alpine@sha256:`, ` AS builder`)
|
|
assertDigestPinnedDockerStage(t, dockerfile, `FROM alpine:3.24@sha256:`, ``)
|
|
|
|
composeBytes, err := os.ReadFile(repoFile("tests", "integration", "docker-compose.test.yml"))
|
|
if err != nil {
|
|
t.Fatalf("read integration compose file: %v", err)
|
|
}
|
|
compose := string(composeBytes)
|
|
if !regexpDigestPinnedImage(`alpine:3.24`, compose) {
|
|
t.Fatal("integration seed image must use the governed Alpine line pinned by a full immutable digest")
|
|
}
|
|
if strings.Contains(dockerfile, "golang:1.23-alpine") || strings.Contains(compose, "image: alpine:3.20\n") {
|
|
t.Fatal("integration containers must not restore retired toolchain or runtime lines")
|
|
}
|
|
}
|
|
|
|
func regexpDigestPinnedImage(image string, content string) bool {
|
|
pin := regexp.QuoteMeta(image) + `@sha256:[0-9a-f]{64}`
|
|
// The same-run CI bundle uses this fixed override; the local default must
|
|
// still be a complete governed pin. Do not admit arbitrary interpolation.
|
|
pattern := regexp.MustCompile(`(?m)^[ \t]*image:[ \t]*(?:` + pin + `|\$\{PULSE_E2E_SEED_IMAGE:-` + pin + `\})[ \t]*\r?$`)
|
|
return pattern.MatchString(content)
|
|
}
|
|
|
|
func TestIntegrationContainerImagePinForms(t *testing.T) {
|
|
pin := "alpine:3.24@sha256:" + strings.Repeat("a", 64)
|
|
for _, tc := range []struct {
|
|
name string
|
|
value string
|
|
want bool
|
|
}{
|
|
{"literal", "image: " + pin + "\n", true},
|
|
{"indented-literal", " image: " + pin + "\n", true},
|
|
{"same-run-override", " image: ${PULSE_E2E_SEED_IMAGE:-" + pin + "}\n", true},
|
|
{"crlf-override", "\timage:\t${PULSE_E2E_SEED_IMAGE:-" + pin + "} \r\n", true},
|
|
{"unpinned-literal", "image: alpine:3.24\n", false},
|
|
{"unpinned-default", "image: ${PULSE_E2E_SEED_IMAGE:-alpine:3.24}\n", false},
|
|
{"missing-default", "image: ${PULSE_E2E_SEED_IMAGE}\n", false},
|
|
{"retired-line", "image: ${PULSE_E2E_SEED_IMAGE:-" + strings.Replace(pin, "3.24", "3.20", 1) + "}\n", false},
|
|
{"mutable-line", "image: ${PULSE_E2E_SEED_IMAGE:-" + strings.Replace(pin, "3.24", "latest", 1) + "}\n", false},
|
|
{"other-variable", "image: ${OTHER_IMAGE:-" + pin + "}\n", false},
|
|
{"unset-only-default", "image: ${PULSE_E2E_SEED_IMAGE-" + pin + "}\n", false},
|
|
{"alternate-operator", "image: ${PULSE_E2E_SEED_IMAGE:+" + pin + "}\n", false},
|
|
{"short-literal-digest", "image: " + pin[:len(pin)-1] + "\n", false},
|
|
{"short-default-digest", "image: ${PULSE_E2E_SEED_IMAGE:-" + pin[:len(pin)-1] + "}\n", false},
|
|
{"long-default-digest", "image: ${PULSE_E2E_SEED_IMAGE:-" + pin + "a}\n", false},
|
|
{"invalid-default-digest", "image: ${PULSE_E2E_SEED_IMAGE:-" + strings.Replace(pin, "sha256:a", "sha256:g", 1) + "}\n", false},
|
|
{"missing-close", "image: ${PULSE_E2E_SEED_IMAGE:-" + pin + "\n", false},
|
|
{"default-suffix", "image: ${PULSE_E2E_SEED_IMAGE:-" + pin + ":other}\n", false},
|
|
{"override-suffix", "image: ${PULSE_E2E_SEED_IMAGE:-" + pin + "}/other\n", false},
|
|
{"multiline-value", "image:\n" + pin + "\n", false},
|
|
{"multiline-default", "image: ${PULSE_E2E_SEED_IMAGE:-\n" + pin + "}\n", false},
|
|
{"commented-pin", "# image: " + pin + "\nimage: alpine:latest\n", false},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
if got := regexpDigestPinnedImage("alpine:3.24", tc.value); got != tc.want {
|
|
t.Fatalf("governed seed image admission = %t, want %t", got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|