Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions src/pkg/advisory/filepathref_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package advisory

import "testing"

// Direct branch coverage for splitFilePathRef and isFilePathRef — the parsers
// that decide which finding refs VerifyFindingPaths checks for existence and
// what path it checks. snapshot_test.go exercises them only through the happy
// VerifyFindingPaths flow; these tests pin the edge branches so a parser
// regression shows up here rather than as a wrongly-stale (or wrongly-live)
// finding in a posted digest.

func TestSplitFilePathRef(t *testing.T) {
cases := []struct {
name, ref, want string
}{
{"path with line suffix", "pkg/mint/tokenreview.go:365", "pkg/mint/tokenreview.go"},
{"path without colon", "docs/install.md", "docs/install.md"},
{"non-numeric suffix kept", "cmd/hive:main", "cmd/hive:main"},
{"leading colon kept", ":123", ":123"},
{"empty ref", "", ""},
{"trailing colon kept", "pkg/file.go:", "pkg/file.go:"},
{"only last numeric segment stripped", "a:1:2", "a:1"},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
if got := splitFilePathRef(tc.ref); got != tc.want {
t.Errorf("splitFilePathRef(%q) = %q, want %q", tc.ref, got, tc.want)
}
})
}
}

func TestIsFilePathRef(t *testing.T) {
cases := []struct {
name, ref string
want bool
}{
{"empty is not a path", "", false},
{"gh-number ref", "gh-123", false},
{"repo#number ref", "hive#123", false},
{"owner/repo#number ref", "kubestellar/hive#123", false},
{"plain file path", "docs/install.md", true},
{"path with line", "pkg/advisory/advisory.go:812", true},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
if got := isFilePathRef(tc.ref); got != tc.want {
t.Errorf("isFilePathRef(%q) = %v, want %v", tc.ref, got, tc.want)
}
})
}
}
107 changes: 107 additions & 0 deletions src/pkg/mint/tokenreview_loader_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package mint

import (
"os"
"path/filepath"
"strings"
"testing"
)

// Tests for the projected-token loader and the in-cluster constructor's CA
// branch — the pieces TestNewInClusterTokenReviewAuthenticatorRefusesOutsideACluster
// does not reach.
//
// readFileTrimmed is what lets the mint keep authenticating ITSELF after the
// kubelet rotates the projected ServiceAccount token on disk: it must re-read
// on every call and strip the trailing newline the projection writes. A loader
// that cached, or that passed the newline through, would start failing reviews
// an hour after boot while looking healthy.

func TestReadFileTrimmedRereadsRotatedToken(t *testing.T) {
path := filepath.Join(t.TempDir(), "token")
if err := os.WriteFile(path, []byte(" first-token\n"), 0o600); err != nil {
t.Fatalf("writing token: %v", err)
}

load := readFileTrimmed(path)

got, err := load()
if err != nil {
t.Fatalf("first load: %v", err)
}
if got != "first-token" {
t.Errorf("first load = %q, want %q (whitespace must be trimmed)", got, "first-token")
}

// Rotate the token on disk. The loader must observe the new value: a
// cached read here is the bug the doc comment on readFileTrimmed warns
// about — the process stays healthy while every review starts failing.
if err := os.WriteFile(path, []byte("second-token\n"), 0o600); err != nil {
t.Fatalf("rotating token: %v", err)
}
got, err = load()
if err != nil {
t.Fatalf("load after rotation: %v", err)
}
if got != "second-token" {
t.Errorf("load after rotation = %q, want %q (loader must re-read, not cache)", got, "second-token")
}
}

func TestReadFileTrimmedPropagatesMissingFile(t *testing.T) {
load := readFileTrimmed(filepath.Join(t.TempDir(), "does-not-exist"))
if _, err := load(); err == nil {
t.Error("loading a missing token file succeeded — the error must propagate so review failures are attributable")
}
}

func TestReadFileTrimmedEmptyFileYieldsEmptyToken(t *testing.T) {
path := filepath.Join(t.TempDir(), "token")
if err := os.WriteFile(path, []byte("\n\t \n"), 0o600); err != nil {
t.Fatalf("writing token: %v", err)
}
got, err := readFileTrimmed(path)()
if err != nil {
t.Fatalf("load: %v", err)
}
if got != "" {
t.Errorf("whitespace-only file loaded as %q, want empty string", got)
}
}

// The in-cluster constructor must fail rather than degrade when the
// KUBERNETES_SERVICE_* environment is present but the mounted CA bundle is
// not readable — a half-present cluster environment is a misconfiguration,
// not a cue to fall back to weaker trust.
//
// The assertion is conditional on whether the projected CA path exists so the
// test stays hermetic both on plain hosts (the common case: the path is
// absent, construction must fail naming the CA) and inside a real pod (the
// path exists, construction must succeed against the fake host/port because
// no network I/O happens at construction time).
func TestNewInClusterTokenReviewAuthenticatorCABranch(t *testing.T) {
t.Setenv("KUBERNETES_SERVICE_HOST", "kubernetes.default.svc.hive.invalid")
t.Setenv("KUBERNETES_SERVICE_PORT", "443")

a, err := NewInClusterTokenReviewAuthenticator(testAudience)

if _, statErr := os.Stat(inClusterCAPath); statErr != nil {
// Plain host: the CA bundle is absent, so construction must refuse.
if err == nil {
t.Fatal("built an in-cluster authenticator with no readable CA bundle — it must fail rather than degrade to host trust")
}
if !strings.Contains(err.Error(), "CA bundle") {
t.Errorf("error = %q, want it to name the CA bundle so the operator knows what is missing", err)
}
return
}

// Real pod: the projected CA exists, so construction succeeds without
// touching the network.
if err != nil {
t.Fatalf("NewInClusterTokenReviewAuthenticator with a present CA bundle: %v", err)
}
if a == nil {
t.Fatal("nil authenticator with nil error")
}
}
Loading