From 47e43f59c5ea8c561422cf388da1e21bfa14bcb7 Mon Sep 17 00:00:00 2001 From: Sai Sanjay Date: Mon, 16 Feb 2026 00:45:05 +0530 Subject: [PATCH 01/10] security: add NetworkPolicy configuration for ATC deployment to address security advisory - GHSA-965m-v4cc-6334 Signed-off-by: Sai Sanjay --- cmd/atc-installer/installer/run.go | 45 ++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/cmd/atc-installer/installer/run.go b/cmd/atc-installer/installer/run.go index b518816b..935271c5 100644 --- a/cmd/atc-installer/installer/run.go +++ b/cmd/atc-installer/installer/run.go @@ -14,6 +14,7 @@ import ( appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + networkingv1 "k8s.io/api/networking/v1" rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" @@ -295,12 +296,56 @@ func Run(cfg Config) (flight.Stages, error) { }, } + networkPolicy := &networkingv1.NetworkPolicy{ + TypeMeta: metav1.TypeMeta{ + Kind: "NetworkPolicy", + APIVersion: networkingv1.SchemeGroupVersion.Identifier(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: flight.Release() + "-atc", + Namespace: flight.Namespace(), + }, + Spec: networkingv1.NetworkPolicySpec{ + PodSelector: metav1.LabelSelector{ + MatchLabels: selector, + }, + PolicyTypes: []networkingv1.PolicyType{ + networkingv1.PolicyTypeIngress, + }, + Ingress: []networkingv1.NetworkPolicyIngressRule{ + { + From: []networkingv1.NetworkPolicyPeer{ + { + NamespaceSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "kubernetes.io/metadata.name": "kube-system", + }, + }, + PodSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "component": "kube-apiserver", + }, + }, + }, + }, + Ports: []networkingv1.NetworkPolicyPort{ + { + Protocol: ptr.To(corev1.ProtocolTCP), + Port: ptr.To(intstr.FromInt(cfg.Port)), + }, + }, + }, + }, + }, + } + return flight.Stages{ { svc, tlsSecret, account, binding, + networkPolicy, }, { // By moving the deployment deletion into a later stage, this means we will also delete it first From e92b303eee23b5859b1f2c36fc42eb85c950316a Mon Sep 17 00:00:00 2001 From: Sai Sanjay Date: Wed, 18 Feb 2026 20:56:48 +0530 Subject: [PATCH 02/10] security: migrate from kind to k3d for cluster management in tests and pipeline Signed-off-by: Sai Sanjay --- .github/workflows/pipeline.yaml | 2 +- Taskfile.yml | 2 +- cmd/atc/main_test.go | 33 +++++++++++++++++---------------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/.github/workflows/pipeline.yaml b/.github/workflows/pipeline.yaml index a67b2176..f1b6c637 100644 --- a/.github/workflows/pipeline.yaml +++ b/.github/workflows/pipeline.yaml @@ -36,7 +36,7 @@ jobs: shell: bash run: | go install github.com/go-task/task/v3/cmd/task@latest - go install sigs.k8s.io/kind@latest + go install github.com/k3d-io/k3d/v5@latest task test diff --git a/Taskfile.yml b/Taskfile.yml index 70e2839e..3ef321a9 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -19,7 +19,7 @@ tasks: update-tools: cmds: - - go install sigs.k8s.io/kind@latest + - go install github.com/k3d-io/k3d/v5@latest update-deps: cmds: diff --git a/cmd/atc/main_test.go b/cmd/atc/main_test.go index 25f061d4..4128d61a 100644 --- a/cmd/atc/main_test.go +++ b/cmd/atc/main_test.go @@ -59,19 +59,20 @@ func TestMain(m *testing.M) { must(os.RemoveAll("./test_output")) must(os.MkdirAll("./test_output", 0o755)) - must(x.X("kind delete cluster --name=atc-test")) - - must(x.X("kind create cluster --name=atc-test --config -", x.Input(strings.NewReader(` - kind: Cluster - apiVersion: kind.x-k8s.io/v1alpha4 - nodes: - - role: control-plane - extraPortMappings: - - containerPort: 30000 - hostPort: 80 - listenAddress: "127.0.0.1" - protocol: TCP - `)))) + must(x.X("k3d cluster delete atc-test")) + + must(x.X("k3d cluster create --config -", x.Input(strings.NewReader(` + apiVersion: k3d.io/v1alpha5 + kind: Simple + metadata: + name: atc-test + servers: 1 + agents: 0 + ports: + - port: 0.0.0.0:80:30000@server:0 + nodeFilters: + - loadbalancer + `)))) if ci, _ := strconv.ParseBool(os.Getenv("CI")); !ci { must(x.X("kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml")) @@ -91,13 +92,13 @@ func TestMain(m *testing.M) { "docker build -t yokecd/atc:test -f Dockerfile.atc .", x.Dir("../.."), )) - must(x.X("kind load --name=atc-test docker-image yokecd/atc:test")) + must(x.X("k3d image import yokecd/atc:test --cluster atc-test")) must(x.X("docker build -t yokecd/wasmcache:test -f ./internal/testing/Dockerfile.wasmcache ../..")) - must(x.X("kind load --name=atc-test docker-image yokecd/wasmcache:test")) + must(x.X("k3d image import yokecd/wasmcache:test --cluster atc-test")) must(x.X("docker build -t yokecd/c4ts:test -f ./internal/testing/Dockerfile.c4ts ./internal/testing")) - must(x.X("kind load --name=atc-test docker-image yokecd/c4ts:test")) + must(x.X("k3d image import yokecd/c4ts:test --cluster atc-test")) client := internal.Must2(k8s.NewClientFromKubeConfig(home.Kubeconfig)) commander := yoke.FromK8Client(client) From 7f048359afbb95a8782fcb778c5443be3ca14c04 Mon Sep 17 00:00:00 2001 From: Sai Sanjay Date: Wed, 18 Feb 2026 22:09:05 +0530 Subject: [PATCH 03/10] improve indentation k3d config Signed-off-by: Sai Sanjay --- cmd/atc/main_test.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/cmd/atc/main_test.go b/cmd/atc/main_test.go index 4128d61a..93aa3a6f 100644 --- a/cmd/atc/main_test.go +++ b/cmd/atc/main_test.go @@ -62,17 +62,17 @@ func TestMain(m *testing.M) { must(x.X("k3d cluster delete atc-test")) must(x.X("k3d cluster create --config -", x.Input(strings.NewReader(` - apiVersion: k3d.io/v1alpha5 - kind: Simple - metadata: - name: atc-test - servers: 1 - agents: 0 - ports: - - port: 0.0.0.0:80:30000@server:0 - nodeFilters: - - loadbalancer - `)))) +apiVersion: k3d.io/v1alpha5 +kind: Simple +metadata: + name: atc-test +servers: 1 +agents: 0 +ports: + - port: 0.0.0.0:80:30000@server:0 + nodeFilters: + - loadbalancer +`)))) if ci, _ := strconv.ParseBool(os.Getenv("CI")); !ci { must(x.X("kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml")) From e27dd2ec883bce1cc2ce25692b7608538ab75f35 Mon Sep 17 00:00:00 2001 From: Sai Sanjay Date: Wed, 18 Feb 2026 22:36:15 +0530 Subject: [PATCH 04/10] security: add test to verify ATC network policy restricts access to kube-system namespace Signed-off-by: Sai Sanjay --- cmd/atc/main_test.go | 108 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/cmd/atc/main_test.go b/cmd/atc/main_test.go index 93aa3a6f..30318f07 100644 --- a/cmd/atc/main_test.go +++ b/cmd/atc/main_test.go @@ -5,6 +5,7 @@ import ( "encoding/base64" "encoding/json" "fmt" + "io" "os" "slices" "strconv" @@ -147,6 +148,113 @@ ports: os.Exit(m.Run()) } +func TestAdmissionExclusiveToKubeSystem(t *testing.T) { + client, err := k8s.NewClientFromKubeConfig(home.Kubeconfig) + require.NoError(t, err) + + ctx := context.Background() + commander := yoke.FromK8Client(client) + + // Create a test namespace + testNamespace := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-admission-exclusive", + }, + } + // Create the namespace via yoke + require.NoError(t, client.EnsureNamespace(ctx, testNamespace.Name)) + + defer func() { + // Clean up the test namespace + require.NoError(t, client.Clientset.CoreV1().Namespaces().Delete(ctx, testNamespace.Name, metav1.DeleteOptions{})) + }() + + releaseName := "test-admission-curl" + //Deploy the curl pod as a yoke release + require.NoError(t, commander.Takeoff(ctx, yoke.TakeoffParams{ + Release: releaseName, + Namespace: testNamespace.Name, + Flight: yoke.FlightParams{ + Input: internal.JSONReader(corev1.Pod{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Pod", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: releaseName, + Namespace: testNamespace.Name, + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "curl", + Image: "curlimages/curl:latest", + Command: []string{ + "sh", "-c", + "curl -v http://atc-atc.atc:80/live && sleep 3600", + }, + }, + }, + RestartPolicy: corev1.RestartPolicyNever, + }, + }), + }, + CrossNamespace: true, // pod namespace differs from release namespace? No, same here — omit if same + Wait: 30 * time.Second, + Poll: time.Second, + })) + + // Mayday to ensure cleanup of the release and its resources. + defer func() { + require.NoError(t, commander.Mayday(ctx, yoke.MaydayParams{ + Release: releaseName, + Namespace: testNamespace.Name, + })) + }() + + // Poll pod state and logs using client-go + testutils.EventuallyNoErrorf( + t, + func() error { + pod, err := client.Clientset.CoreV1().Pods(testNamespace.Name).Get(ctx, releaseName, metav1.GetOptions{}) + if err != nil { + return err + } + switch pod.Status.Phase { + case corev1.PodPending, corev1.PodRunning: + return fmt.Errorf("pod is in %s state, waiting", pod.Status.Phase) + case corev1.PodSucceeded: + // curl exited 0 — it connected to ATC, which should not be allowed + return fmt.Errorf("pod curl succeeded unexpectedly: ATC should be inaccessible from non-kube-system namespace") + } + // PodFailed: curl exited non-zero — expected; fall through to log check + logs, err := client.Clientset.CoreV1().Pods(testNamespace.Name). + GetLogs(releaseName, &corev1.PodLogOptions{}).Stream(ctx) + if err != nil { + return fmt.Errorf("failed to get pod logs: %w", err) + } + defer func(logs io.ReadCloser) { + err := logs.Close() + if err != nil { + fmt.Printf("failed to close logs stream: %v", err) + } + }(logs) + logData, err := io.ReadAll(logs) + if err != nil { + return fmt.Errorf("failed to read pod logs: %w", err) + } + logStr := string(logData) + if strings.Contains(logStr, "Connected to") || strings.Contains(logStr, "200 OK") { + return fmt.Errorf("pod should not access ATC, but logs show success: %s", logStr) + } + return nil + }, + time.Second, + 30*time.Second, + "pod curl to ATC should fail, but it did not", + ) +} + func TestAirTrafficController(t *testing.T) { client, err := k8s.NewClientFromKubeConfig(home.Kubeconfig) require.NoError(t, err) From 21e8f8e433a32d5621ae9bbeb5fd71011584a88d Mon Sep 17 00:00:00 2001 From: Sai Sanjay Date: Wed, 18 Feb 2026 22:40:20 +0530 Subject: [PATCH 05/10] chore: add kind installation to pipeline and update-tools task Signed-off-by: Sai Sanjay --- .github/workflows/pipeline.yaml | 1 + Taskfile.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/pipeline.yaml b/.github/workflows/pipeline.yaml index f1b6c637..c5fe4932 100644 --- a/.github/workflows/pipeline.yaml +++ b/.github/workflows/pipeline.yaml @@ -37,6 +37,7 @@ jobs: run: | go install github.com/go-task/task/v3/cmd/task@latest go install github.com/k3d-io/k3d/v5@latest + go install sigs.k8s.io/kind@latest task test diff --git a/Taskfile.yml b/Taskfile.yml index 3ef321a9..2415c1af 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -19,6 +19,7 @@ tasks: update-tools: cmds: + - go install sigs.k8s.io/kind@latest - go install github.com/k3d-io/k3d/v5@latest update-deps: From c90ae84ebd733f6561f38f6cc8e5a6ac53fe6338 Mon Sep 17 00:00:00 2001 From: Sai Sanjay Date: Thu, 19 Feb 2026 16:30:14 +0530 Subject: [PATCH 06/10] introduce atc component and refine k3d test cluster setup with port forwarding, coredns wait, and extended timeouts. --- cmd/atc/main_test.go | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/cmd/atc/main_test.go b/cmd/atc/main_test.go index 30318f07..808c7cea 100644 --- a/cmd/atc/main_test.go +++ b/cmd/atc/main_test.go @@ -62,19 +62,17 @@ func TestMain(m *testing.M) { must(x.X("k3d cluster delete atc-test")) - must(x.X("k3d cluster create --config -", x.Input(strings.NewReader(` + must(x.X("k3d cluster create --config - -p 80:30000@loadbalancer", x.Input(strings.NewReader(` apiVersion: k3d.io/v1alpha5 kind: Simple metadata: name: atc-test servers: 1 agents: 0 -ports: - - port: 0.0.0.0:80:30000@server:0 - nodeFilters: - - loadbalancer `)))) + must(x.X("kubectl rollout status deployment/coredns -n kube-system --timeout=120s")) + if ci, _ := strconv.ParseBool(os.Getenv("CI")); !ci { must(x.X("kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml")) must(x.X(`kubectl patch -n kube-system deployment metrics-server --type=json -p [{"op":"add","path":"/spec/template/spec/containers/0/args/-","value":"--kubelet-insecure-tls"}]`)) @@ -199,9 +197,6 @@ func TestAdmissionExclusiveToKubeSystem(t *testing.T) { }, }), }, - CrossNamespace: true, // pod namespace differs from release namespace? No, same here — omit if same - Wait: 30 * time.Second, - Poll: time.Second, })) // Mayday to ensure cleanup of the release and its resources. @@ -250,7 +245,7 @@ func TestAdmissionExclusiveToKubeSystem(t *testing.T) { return nil }, time.Second, - 30*time.Second, + 2*time.Minute, "pod curl to ATC should fail, but it did not", ) } From 5e4e55b9ef932f53794b81bae94863b4ba5c8b60 Mon Sep 17 00:00:00 2001 From: Sai Sanjay Date: Thu, 19 Feb 2026 20:57:13 +0530 Subject: [PATCH 07/10] increase yoke takeoff timeout for k3d --- cmd/atc/main_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/atc/main_test.go b/cmd/atc/main_test.go index 808c7cea..9f355d58 100644 --- a/cmd/atc/main_test.go +++ b/cmd/atc/main_test.go @@ -118,7 +118,7 @@ agents: 0 Args: []string{"--skip-version-check"}, }, CreateNamespace: true, - Wait: 120 * time.Second, + Wait: 5 * time.Minute, Poll: time.Second, })) From ae076998735f10e54137222fc56be1e9092b460a Mon Sep 17 00:00:00 2001 From: David Desmarais-Michaud Date: Sat, 21 Feb 2026 20:56:01 -0500 Subject: [PATCH 08/10] update pipeline to use k3d context when dumping logs on failure --- .github/workflows/pipeline.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pipeline.yaml b/.github/workflows/pipeline.yaml index c5fe4932..1b6edc20 100644 --- a/.github/workflows/pipeline.yaml +++ b/.github/workflows/pipeline.yaml @@ -44,7 +44,7 @@ jobs: - name: Dump kubectl logs if: failure() run: | - kubectl config use-context kind-atc-test + kubectl config use-context k3d-atc-test kubectl cluster-info dump > k8s_dump.out - name: Upload k8s dump From bb3fda7b82420f15d385dc7eea2c70303188666a Mon Sep 17 00:00:00 2001 From: David Desmarais-Michaud Date: Sun, 22 Feb 2026 13:38:32 -0500 Subject: [PATCH 09/10] debug atc log stream on atc installation failure during tests --- cmd/atc/main_test.go | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/cmd/atc/main_test.go b/cmd/atc/main_test.go index 9f355d58..74c58d5b 100644 --- a/cmd/atc/main_test.go +++ b/cmd/atc/main_test.go @@ -104,7 +104,7 @@ agents: 0 ctx := internal.WithDebugFlag(context.Background(), new(true)) - must(commander.Takeoff(ctx, yoke.TakeoffParams{ + if takeoffErr := commander.Takeoff(ctx, yoke.TakeoffParams{ Release: "atc", Namespace: "atc", Flight: yoke.FlightParams{ @@ -118,10 +118,29 @@ agents: 0 Args: []string{"--skip-version-check"}, }, CreateNamespace: true, - Wait: 5 * time.Minute, + Wait: 2 * time.Minute, Poll: time.Second, - })) + }); takeoffErr != nil { + fmt.Println("[[DEBUG ATC LOG STREAM]]") + pods, err := client.Clientset.CoreV1().Pods("atc").List(ctx, metav1.ListOptions{LabelSelector: "yoke.cd/app=atc"}) + if err != nil { + panic(err) + } + if len(pods.Items) != 1 { + panic(fmt.Errorf("expected 1 atc pod but got: %d", len(pods.Items))) + } + req := client.Clientset.CoreV1().Pods("atc").GetLogs(pods.Items[0].Name, &corev1.PodLogOptions{}) + + rc, err := req.Stream(ctx) + if err != nil { + panic(fmt.Errorf("failed to get atc log stream: %v", err)) + } + if _, err := io.Copy(os.Stdout, rc); err != nil { + panic(fmt.Errorf("failed to copy atc log stream to stdout: %v", err)) + } + panic(takeoffErr) + } must(commander.Takeoff(ctx, yoke.TakeoffParams{ Release: "wasmcache", Namespace: "atc", @@ -168,7 +187,7 @@ func TestAdmissionExclusiveToKubeSystem(t *testing.T) { }() releaseName := "test-admission-curl" - //Deploy the curl pod as a yoke release + // Deploy the curl pod as a yoke release require.NoError(t, commander.Takeoff(ctx, yoke.TakeoffParams{ Release: releaseName, Namespace: testNamespace.Name, From 70c7d0d9f2f6e8301bc8ad12d6707038312935cd Mon Sep 17 00:00:00 2001 From: Sai Sanjay Date: Thu, 12 Mar 2026 02:34:48 +0530 Subject: [PATCH 10/10] test: add K3s image to ATC test configuration. Signed-off-by: Sai Sanjay --- cmd/atc/main_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/atc/main_test.go b/cmd/atc/main_test.go index 74c58d5b..af9b65fa 100644 --- a/cmd/atc/main_test.go +++ b/cmd/atc/main_test.go @@ -67,6 +67,7 @@ apiVersion: k3d.io/v1alpha5 kind: Simple metadata: name: atc-test +image: rancher/k3s:v1.31.4-k3s1 servers: 1 agents: 0 `))))