bastion 0.58.0
ci / personal-data (push) Successful in 4s
ci / test (push) Successful in 4m5s
ci / fuzz (push) Successful in 4m10s

This commit is contained in:
Privatae
2026-10-29 15:54:51 +00:00
parent 081763a675
commit 01889e2a48
37 changed files with 5629 additions and 90 deletions
+237
View File
@@ -0,0 +1,237 @@
package main
import (
"context"
"fmt"
"net"
"strings"
"testing"
)
// RESULT: red before opLocalNetworkDest — on a local box a name that resolves
// to a home network's address was put in the apply's allowlist.
func TestALocalBoxRefusesANameThatResolvesToAPrivateNetworkAtApply(t *testing.T) {
localOpBox(t)
prevOwn, prevRes := opActionOwnAddrs, opActionResolve
opActionOwnAddrs = func() []net.IP { return nil }
opActionResolve = func(_ context.Context, h string) ([]net.IP, error) {
switch h {
case "nas.home.example":
return []net.IP{net.ParseIP("10.0.0.2")}, nil
case "split.example.com":
return []net.IP{net.ParseIP("203.0.113.10"), net.ParseIP("192.168.1.2")}, nil
case "forge.example.com":
return []net.IP{net.ParseIP("203.0.113.10")}, nil
}
return nil, fmt.Errorf("no")
}
t.Cleanup(func() { opActionOwnAddrs, opActionResolve = prevOwn, prevRes })
for _, d := range []string{"nas.home.example:80", "split.example.com:443"} {
if _, err := opResolveDests(context.Background(), []string{d}); err == nil ||
!strings.Contains(err.Error(), "private network") {
t.Errorf("%s: a local box resolves it into the allowlist: %v", d, err)
}
}
got, err := opResolveDests(context.Background(), []string{"forge.example.com:443"})
if err != nil || len(got.Addrs) != 1 || got.Addrs[0] != "203.0.113.10" {
t.Fatalf("a public name resolves to its address: %+v %v", got, err)
}
// An anchored fleet keeps the same name.
setupBox(t)
if got, err := opResolveDests(context.Background(), []string{"nas.home.example:80"}); err != nil || got.Addrs[0] != "10.0.0.2" {
t.Fatalf("an anchored box resolves a private control plane: %+v %v", got, err)
}
}
// A destination written as an address is judged again at apply by the anchor
// the machine has then: an op held while the machine was anchored does not
// reach a private address after the anchor is gone.
func TestAPrivateDestinationHeldWhileAnchoredIsRefusedAtApplyOnceTheAnchorIsGone(t *testing.T) {
setupBox(t)
prevOwn := opActionOwnAddrs
opActionOwnAddrs = func() []net.IP { return nil }
t.Cleanup(func() { opActionOwnAddrs = prevOwn })
for _, d := range []string{"10.0.0.2:80", "[::ffff:10.0.0.2]:80"} {
if _, err := opResolveDests(context.Background(), []string{d}); err != nil {
t.Fatalf("%s: an anchored box reaches its private control plane: %v", d, err)
}
}
localOpBox(t)
for _, d := range []string{"10.0.0.2:80", "[::ffff:10.0.0.2]:80"} {
if _, err := opResolveDests(context.Background(), []string{d}); err == nil || !strings.Contains(err.Error(), "private network") {
t.Errorf("%s: held while anchored, reached after the anchor is gone: %v", d, err)
}
}
}
// A verb fetches too: tree.checkout fetches its repo, and k8s.set_image
// fetches its repo to check ancestry, each with the bastion's own root and
// outside the program's sandbox. On a local machine that fetch is held to
// the rule a destination is: a repository whose host resolves to a private
// network is never fetched, and no git runs for it. An interpreter: none op
// is nothing but verbs, so this is the whole of its reach.
//
// RESULT: red before opFetchPin — the ancestry fetch ran git against the
// name, which git resolved itself, so a name on a home network was fetched.
func TestALocalBoxNeverFetchesAVerbsRepositoryFromAPrivateNetwork(t *testing.T) {
localOpBox(t)
prevOwn, prevRes := opActionOwnAddrs, opActionResolve
opActionOwnAddrs = func() []net.IP { return nil }
opActionResolve = func(_ context.Context, h string) ([]net.IP, error) {
switch h {
case "nas.home.example":
return []net.IP{net.ParseIP("10.0.0.2")}, nil
case "split.example.com":
return []net.IP{net.ParseIP("203.0.113.10"), net.ParseIP("::ffff:192.168.1.2")}, nil
case "meta.example.com":
return []net.IP{net.ParseIP("169.254.169.254")}, nil
}
return nil, fmt.Errorf("no")
}
t.Cleanup(func() { opActionOwnAddrs, opActionResolve = prevOwn, prevRes })
older, newer := strings.Repeat("a", 40), strings.Repeat("b", 40)
for repo, want := range map[string]string{
"https://nas.home.example/acme/app.git": "private network",
"https://split.example.com/acme/app.git": "private network",
"https://meta.example.com/acme/app.git": "link-local",
} {
err := opAncestryByFetch(repo, older, newer, nil)
if err == nil || !strings.Contains(err.Error(), want) {
t.Errorf("%s: a local box fetched it: %v", repo, err)
}
}
// The pin a public repository is fetched under: git is held to the
// address checked here and never looks the name up again.
prevGit := opGitPinnable
opGitPinnable = func() string { return "" }
t.Cleanup(func() { opGitPinnable = prevGit })
opActionResolve = func(_ context.Context, h string) ([]net.IP, error) {
return []net.IP{net.ParseIP("2001:db8::10")}, nil
}
if pin, err := opFetchPin(context.Background(), "https://forge.example.com:8443/acme/app.git"); err != nil ||
strings.Join(pin, " ") != "-c http.curloptResolve=forge.example.com:8443:[2001:db8::10]" {
t.Fatalf("a public repository is fetched pinned to its address: %q %v", pin, err)
}
// A git that would drop the pin is refused, never run unpinned.
opGitPinnable = func() string { return "git 2.34 cannot hold a fetch to one address" }
if _, err := opFetchPin(context.Background(), "https://forge.example.com/acme/app.git"); err == nil {
t.Fatal("a git that ignores the pin fetched unpinned")
}
// An anchored fleet fetches from its private forge, pinned to it.
opGitPinnable = func() string { return "" }
setupBox(t)
opActionResolve = func(_ context.Context, h string) ([]net.IP, error) {
return []net.IP{net.ParseIP("10.0.0.2")}, nil
}
if pin, err := opFetchPin(context.Background(), "https://nas.home.example/acme/app.git"); err != nil ||
strings.Join(pin, " ") != "-c http.curloptResolve=nas.home.example:443:10.0.0.2" {
t.Fatalf("an anchored box fetches from its private forge: %q %v", pin, err)
}
}
// An anchored machine keeps its fleet's private forges, but a verb's fetch
// there is still never this machine, its loopback, a link-local address or a
// cloud's metadata service: a name steered to one is refused before git runs.
//
// RESULT: red before opFetchPin ran on anchored machines — git fetched each
// name itself, whatever it resolved to.
func TestAnAnchoredBoxNeverFetchesAVerbsRepositoryFromItselfOrTheMetadataService(t *testing.T) {
setupBox(t)
prevOwn, prevRes := opActionOwnAddrs, opActionResolve
opActionOwnAddrs = func() []net.IP { return []net.IP{net.ParseIP("203.0.113.99")} }
opActionResolve = func(_ context.Context, h string) ([]net.IP, error) {
switch h {
case "lo.example.com":
return []net.IP{net.ParseIP("127.0.0.1")}, nil
case "mapped.example.com":
return []net.IP{net.ParseIP("203.0.113.10"), net.ParseIP("::ffff:127.0.0.1")}, nil
case "meta.example.com":
return []net.IP{net.ParseIP("169.254.169.254")}, nil
case "ali.example.com":
return []net.IP{net.ParseIP("100.100.100.200")}, nil
case "self.example.com":
return []net.IP{net.ParseIP("203.0.113.99")}, nil
}
return nil, fmt.Errorf("no")
}
t.Cleanup(func() { opActionOwnAddrs, opActionResolve = prevOwn, prevRes })
older, newer := strings.Repeat("a", 40), strings.Repeat("b", 40)
for repo, want := range map[string]string{
"https://lo.example.com/acme/app.git": "loopback",
"https://mapped.example.com/acme/app.git": "loopback",
"https://meta.example.com/acme/app.git": "link-local",
"https://ali.example.com/acme/app.git": "metadata service",
"https://self.example.com/acme/app.git": "this machine",
} {
err := opAncestryByFetch(repo, older, newer, nil)
if err == nil || !strings.Contains(err.Error(), want) {
t.Errorf("%s: an anchored box fetched it: %v", repo, err)
}
}
}
// k8s.set_image hands an image to the cluster, and the machine's container
// runtime pulls it by name, outside the bastion's walls. On a local machine
// an image whose registry is on the private network around it is refused
// where the bastion takes the image, so the runtime is never sent there; a
// Docker Hub repository and a public registry pass; an anchored fleet keeps
// its private registry.
//
// RESULT: red before opRegistryOK — the plan took a receipt for an image on a
// home network's registry and went on to the live image's record.
func TestALocalBoxNeverPutsLiveAnImageFromARegistryOnItsNetwork(t *testing.T) {
localOpBox(t)
prevOwn, prevRes := opActionOwnAddrs, opActionResolve
opActionOwnAddrs = func() []net.IP { return nil }
opActionResolve = func(_ context.Context, h string) ([]net.IP, error) {
switch h {
case "nas.home.example":
return []net.IP{net.ParseIP("10.0.0.2")}, nil
case "registry.example.com":
return []net.IP{net.ParseIP("203.0.113.10")}, nil
}
return nil, fmt.Errorf("no")
}
t.Cleanup(func() { opActionOwnAddrs, opActionResolve = prevOwn, prevRes })
useAncestry(t, func(_, _, _ string, _ []string) error { return nil })
ctx := context.Background()
commit := strings.Repeat("c", 40)
for i, tc := range []struct{ image, want string }{
{"nas.home.example:5000/acme/web", "private network"},
{"10.0.0.2:5000/acme/web", "private network"},
{"192.168.1.2/acme/web", "private network"},
{"localhost:5000/acme/web", "loopback"},
{"169.254.169.254/acme/web", "link-local"},
{"registry.example.com/acme/web", ""},
{"acme/web", ""},
} {
digest := "sha256:" + strings.Repeat(fmt.Sprintf("%x", i+1), 64)
if _, err := opIssueReceipts("r", "web-build", strings.Repeat("e", 64), "{}", []opResultImage{{Image: tc.image,
Digest: digest, Source: tRepo, Commit: commit}}); err != nil {
t.Fatal(err)
}
f := &fakeKube{containers: map[string]string{"bridge": tc.image + "@sha256:" + strings.Repeat("0", 64)}}
useFakeKube(t, f)
line := setImageLine(digest)
line.Args["image"] = tc.image
_, err := opImagePlan(ctx, line, nil)
if tc.want != "" {
if err == nil || !strings.Contains(err.Error(), tc.want) || !strings.Contains(err.Error(), "comes from the registry") {
t.Errorf("%s: a local box would put it live: %v", tc.image, err)
}
if _, err := opImageDo(ctx, line, nil, nil, ""); err == nil || len(f.sets()) != 0 {
t.Errorf("%s: and set it: %v %v", tc.image, err, f.sets())
}
} else if err != nil && strings.Contains(err.Error(), "comes from the registry") {
t.Errorf("%s: a public registry is refused: %v", tc.image, err)
}
}
// An anchored fleet keeps its private registry.
setupBox(t)
if err := opRegistryOK(ctx, "nas.home.example:5000/acme/web@sha256:"+strings.Repeat("1", 64)); err != nil {
t.Fatalf("an anchored box pulls from its private registry: %v", err)
}
}