From 7d1a495f55f0e859120bc8f901a88ed5146dad54 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 6 Sep 2026 12:45:40 -0700 Subject: [PATCH 01/10] chore: bump oss/go/microsoft/golang from 1.26.6-1 to 1.26.8-1 in /docker (#879) Bumps oss/go/microsoft/golang from 1.26.6-1 to 1.26.8-1. --- updated-dependencies: - dependency-name: oss/go/microsoft/golang dependency-version: 1.26.8-1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- docker/hub-agent.Dockerfile | 2 +- docker/member-agent.Dockerfile | 2 +- docker/refresh-token.Dockerfile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/hub-agent.Dockerfile b/docker/hub-agent.Dockerfile index 99a813377..e846747d9 100644 --- a/docker/hub-agent.Dockerfile +++ b/docker/hub-agent.Dockerfile @@ -8,7 +8,7 @@ # Segmentation fault" / "cgo: gcc produced no output" in runtime/cgo and net) # and, when it did not crash, took over an hour per image. Only the final # distroless stage is per-target, and it runs no commands. -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/oss/go/microsoft/golang:1.26.6-1 AS builder +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/oss/go/microsoft/golang:1.26.8-1 AS builder WORKDIR /workspace # Copy the Go Modules manifests diff --git a/docker/member-agent.Dockerfile b/docker/member-agent.Dockerfile index f05cf953b..1984568d9 100644 --- a/docker/member-agent.Dockerfile +++ b/docker/member-agent.Dockerfile @@ -8,7 +8,7 @@ # Segmentation fault" / "cgo: gcc produced no output" in runtime/cgo and net) # and, when it did not crash, took over an hour per image. Only the final # distroless stage is per-target, and it runs no commands. -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/oss/go/microsoft/golang:1.26.6-1 AS builder +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/oss/go/microsoft/golang:1.26.8-1 AS builder WORKDIR /workspace # Copy the Go Modules manifests diff --git a/docker/refresh-token.Dockerfile b/docker/refresh-token.Dockerfile index 75b2a98a8..55271f4fc 100644 --- a/docker/refresh-token.Dockerfile +++ b/docker/refresh-token.Dockerfile @@ -8,7 +8,7 @@ # Segmentation fault" / "cgo: gcc produced no output" in runtime/cgo and net) # and, when it did not crash, took over an hour per image. Only the final # distroless stage is per-target, and it runs no commands. -FROM --platform=$BUILDPLATFORM mcr.microsoft.com/oss/go/microsoft/golang:1.26.6-1 AS builder +FROM --platform=$BUILDPLATFORM mcr.microsoft.com/oss/go/microsoft/golang:1.26.8-1 AS builder WORKDIR /workspace # Copy the Go Modules manifests From 43511e70f143100cb5deceaef8ee687eaa93b821 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Sep 2026 13:15:02 +1000 Subject: [PATCH 02/10] chore: bump step-security/harden-runner from 2.21.0 to 2.21.1 (#877) --- .github/workflows/codespell.yml | 2 +- .github/workflows/workflow-lint.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index 35f0d7383..7991f3002 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden Runner - uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 + uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1 with: egress-policy: audit diff --git a/.github/workflows/workflow-lint.yml b/.github/workflows/workflow-lint.yml index 87423fa1c..532818b2c 100644 --- a/.github/workflows/workflow-lint.yml +++ b/.github/workflows/workflow-lint.yml @@ -22,7 +22,7 @@ jobs: timeout-minutes: 10 steps: - name: Harden Runner - uses: step-security/harden-runner@05e31511f85b41b11d1cf0ef85d0992719546e2c # v2.21.0 + uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1 with: egress-policy: audit From 60dea368d151fe3529b98e89017ec2dc50a89671 Mon Sep 17 00:00:00 2001 From: Chen Yu Date: Tue, 8 Sep 2026 07:15:47 +0800 Subject: [PATCH 03/10] feat: tweak the Trivy pipeline so that issues can be re-used and superseded (#885) Minor fixes Signed-off-by: michaelawyu --- .github/workflows/trivy.yml | 65 +++++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/.github/workflows/trivy.yml b/.github/workflows/trivy.yml index 5c5fe85f2..cb897bfc3 100644 --- a/.github/workflows/trivy.yml +++ b/.github/workflows/trivy.yml @@ -1,7 +1,7 @@ name: Trivy Vulnerability Scanner on: schedule: - - cron: '0 6 * * *' # Daily at 6:00 AM UTC + - cron: '0 6 * * *' # Daily at 6:00 AM UTC; findings are reported into a single issue per ISO week push: branches: - main @@ -142,9 +142,9 @@ jobs: run: | { echo 'body< { + const d = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate())); + d.setUTCDate(d.getUTCDate() + 4 - (d.getUTCDay() || 7)); + const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1)); + const week = Math.ceil(((d - yearStart) / 86400000 + 1) / 7); + return `${d.getUTCFullYear()}-W${String(week).padStart(2, '0')}`; + }; + + const currentWeek = isoWeek(new Date()); + const title = `fix: address trivy CVEs found in ${currentWeek}`; const securityTeam = '@kubefleet-dev/kubefleet-secops'; const body = `${process.env.ISSUE_BODY}\n\n### Security owners\n${securityTeam}`; - // Check if an open issue already exists for today - const existing = await github.rest.issues.listForRepo({ + // Every report this workflow files carries these labels; they are the only handle used to find prior reports. + const reportLabels = ['security', 'trivy']; + + const open = await github.paginate(github.rest.issues.listForRepo, { owner: context.repo.owner, repo: context.repo.repo, state: 'open', - labels: 'security,trivy', + labels: reportLabels.join(','), + sort: 'created', + direction: 'desc', per_page: 100 }); - const issue = existing.data.find(i => i.title === title); - if (issue) { + // listForRepo also returns pull requests, which are never trivy reports. + const reports = open.filter(i => !i.pull_request); + + const newest = reports[0]; + const thisWeek = newest && isoWeek(new Date(newest.created_at)) === currentWeek ? newest : null; + + if (thisWeek) { await github.rest.issues.update({ owner: context.repo.owner, repo: context.repo.repo, - issue_number: issue.number, + issue_number: thisWeek.number, body: body }); - console.log('Updated the existing issue with the current scan and security team mention.'); + console.log(`Updated issue #${thisWeek.number} with the current scan.`); } else { - await github.rest.issues.create({ + const created = await github.rest.issues.create({ owner: context.repo.owner, repo: context.repo.repo, title: title, body: body, - labels: ['security', 'trivy'] + labels: reportLabels + }); + console.log(`Created issue #${created.data.number} for ${currentWeek}.`); + } + + // Any other open report predates this week; the current one supersedes it. + for (const stale of reports.filter(i => i.number !== thisWeek?.number)) { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: stale.number, + body: `Superseded by the scan reported in \`${title}\`; closing this stale report.` + }); + await github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: stale.number, + state: 'closed', + state_reason: 'not_planned' }); + console.log(`Closed stale issue #${stale.number} (created ${stale.created_at}).`); } env: ISSUE_BODY: ${{ steps.vuln-summary.outputs.body }} From 6e727a76177288231099f46e97103fbf0e4600d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Sep 2026 08:29:33 +1000 Subject: [PATCH 04/10] chore: bump distroless/base from `2d7d29b` to `d199d20` in /docker (#878) --- docker/hub-agent.Dockerfile | 2 +- docker/member-agent.Dockerfile | 2 +- docker/refresh-token.Dockerfile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/hub-agent.Dockerfile b/docker/hub-agent.Dockerfile index e846747d9..651bb9016 100644 --- a/docker/hub-agent.Dockerfile +++ b/docker/hub-agent.Dockerfile @@ -62,7 +62,7 @@ RUN echo "Building hubagent with GOOS=${TARGETOS} GOARCH=${TARGETARCH} CC=$(read # The pinned digest must reference a multi-arch image index so BuildKit can # resolve the matching base layer for each target architecture. # Refer to https://github.com/GoogleContainerTools/distroless for more details -FROM gcr.io/distroless/base:nonroot@sha256:2d7d29b504e7166f6d0c7655a18ebf5def5b37b029f8c4f8667e434ba774844f +FROM gcr.io/distroless/base:nonroot@sha256:d199d20fb09c898d8822ae5cbd5cf3c6d424e9b5e1fc2eb9a719a7752cd9d861 WORKDIR / COPY --link --from=builder /workspace/hubagent . USER 65532:65532 diff --git a/docker/member-agent.Dockerfile b/docker/member-agent.Dockerfile index 1984568d9..982f4343e 100644 --- a/docker/member-agent.Dockerfile +++ b/docker/member-agent.Dockerfile @@ -62,7 +62,7 @@ RUN echo "Building memberagent with GOOS=${TARGETOS} GOARCH=${TARGETARCH} CC=$(r # The pinned digest must reference a multi-arch image index so BuildKit can # resolve the matching base layer for each target architecture. # Refer to https://github.com/GoogleContainerTools/distroless for more details -FROM gcr.io/distroless/base:nonroot@sha256:2d7d29b504e7166f6d0c7655a18ebf5def5b37b029f8c4f8667e434ba774844f +FROM gcr.io/distroless/base:nonroot@sha256:d199d20fb09c898d8822ae5cbd5cf3c6d424e9b5e1fc2eb9a719a7752cd9d861 WORKDIR / COPY --link --from=builder /workspace/memberagent . USER 65532:65532 diff --git a/docker/refresh-token.Dockerfile b/docker/refresh-token.Dockerfile index 55271f4fc..846ee522f 100644 --- a/docker/refresh-token.Dockerfile +++ b/docker/refresh-token.Dockerfile @@ -63,7 +63,7 @@ RUN echo "Building refreshtoken with GOOS=${TARGETOS} GOARCH=${TARGETARCH} CC=$( # The pinned digest must reference a multi-arch image index so BuildKit can # resolve the matching base layer for each target architecture. # Refer to https://github.com/GoogleContainerTools/distroless for more details -FROM gcr.io/distroless/base:nonroot@sha256:2d7d29b504e7166f6d0c7655a18ebf5def5b37b029f8c4f8667e434ba774844f +FROM gcr.io/distroless/base:nonroot@sha256:d199d20fb09c898d8822ae5cbd5cf3c6d424e9b5e1fc2eb9a719a7752cd9d861 WORKDIR / COPY --link --from=builder /workspace/refreshtoken . USER 65532:65532 From a746c1d472799344b5be364ba78d510755b07068 Mon Sep 17 00:00:00 2001 From: Chen Yu Date: Wed, 9 Sep 2026 08:41:12 +0800 Subject: [PATCH 05/10] feat: [FEP-0001] add accessor interface for placement policy and related APIs (#827) Merging this to unblock progress. --- .../placement/v1alpha1/interface.go | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 apis/kubefleet.dev/placement/v1alpha1/interface.go diff --git a/apis/kubefleet.dev/placement/v1alpha1/interface.go b/apis/kubefleet.dev/placement/v1alpha1/interface.go new file mode 100644 index 000000000..bfc3100d4 --- /dev/null +++ b/apis/kubefleet.dev/placement/v1alpha1/interface.go @@ -0,0 +1,150 @@ +/* +Copyright 2026 The KubeFleet Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "sigs.k8s.io/controller-runtime/pkg/client" +) + +// Verify the implementation of the accessor interfaces for the placement policy, +// placement resource snapshot, and placement binding resources. +var _ PlacementPolicyAccessor = &PlacementPolicy{} +var _ PlacementPolicyAccessor = &ClusterPlacementPolicy{} +var _ PlacementResourceSnapshotAccessor = &PlacementResourceSnapshot{} +var _ PlacementResourceSnapshotAccessor = &ClusterPlacementResourceSnapshot{} +var _ PlacementBindingAccessor = &PlacementBinding{} +var _ PlacementBindingAccessor = &ClusterPlacementBinding{} + +// PlacementPolicyAccessor provides unified access to the spec and status of placement policy resources, +// namespace-scoped and cluster-scoped. +// +// +kubebuilder:object:generate=false +type PlacementPolicyAccessor interface { + client.Object + + GetSpec() *PlacementPolicySpec + GetStatus() *PlacementPolicyStatus + + SetSpec(PlacementPolicySpec) + SetStatus(PlacementPolicyStatus) +} + +func (p *PlacementPolicy) GetSpec() *PlacementPolicySpec { + return &p.Spec +} + +func (p *PlacementPolicy) GetStatus() *PlacementPolicyStatus { + return &p.Status +} + +func (p *PlacementPolicy) SetSpec(spec PlacementPolicySpec) { + p.Spec = spec +} + +func (p *PlacementPolicy) SetStatus(status PlacementPolicyStatus) { + p.Status = status +} + +func (p *ClusterPlacementPolicy) GetSpec() *PlacementPolicySpec { + return &p.Spec +} + +func (p *ClusterPlacementPolicy) GetStatus() *PlacementPolicyStatus { + return &p.Status +} + +func (p *ClusterPlacementPolicy) SetSpec(spec PlacementPolicySpec) { + p.Spec = spec +} + +func (p *ClusterPlacementPolicy) SetStatus(status PlacementPolicyStatus) { + p.Status = status +} + +// PlacementResourceSnapshotAccessor provides unified access to the spec of placement resource snapshot resources, +// namespace-scoped and cluster-scoped. +// +// +kubebuilder:object:generate=false +type PlacementResourceSnapshotAccessor interface { + client.Object + + GetSpec() *PlacementResourceSnapshotSpec + + SetSpec(PlacementResourceSnapshotSpec) +} + +func (p *PlacementResourceSnapshot) GetSpec() *PlacementResourceSnapshotSpec { + return &p.Spec +} + +func (p *PlacementResourceSnapshot) SetSpec(spec PlacementResourceSnapshotSpec) { + p.Spec = spec +} + +func (p *ClusterPlacementResourceSnapshot) GetSpec() *PlacementResourceSnapshotSpec { + return &p.Spec +} + +func (p *ClusterPlacementResourceSnapshot) SetSpec(spec PlacementResourceSnapshotSpec) { + p.Spec = spec +} + +// PlacementBindingAccessor provides unified access to the spec and status of placement binding resources, +// namespace-scoped and cluster-scoped. +// +// +kubebuilder:object:generate=false +type PlacementBindingAccessor interface { + client.Object + + GetSpec() *PlacementBindingSpec + GetStatus() *PlacementBindingStatus + + SetSpec(PlacementBindingSpec) + SetStatus(PlacementBindingStatus) +} + +func (p *PlacementBinding) GetSpec() *PlacementBindingSpec { + return &p.Spec +} + +func (p *PlacementBinding) GetStatus() *PlacementBindingStatus { + return &p.Status +} + +func (p *PlacementBinding) SetSpec(spec PlacementBindingSpec) { + p.Spec = spec +} + +func (p *PlacementBinding) SetStatus(status PlacementBindingStatus) { + p.Status = status +} + +func (p *ClusterPlacementBinding) GetSpec() *PlacementBindingSpec { + return &p.Spec +} + +func (p *ClusterPlacementBinding) GetStatus() *PlacementBindingStatus { + return &p.Status +} + +func (p *ClusterPlacementBinding) SetSpec(spec PlacementBindingSpec) { + p.Spec = spec +} + +func (p *ClusterPlacementBinding) SetStatus(status PlacementBindingStatus) { + p.Status = status +} From fcae85a80f8e7d93ee81a643041715c7d99443a1 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 9 Sep 2026 08:22:55 -0700 Subject: [PATCH 06/10] interface: [FEP-0001] prevent unsetting ClusterClaim selector terms (#812) `ClusterClaim.spec.clusterSelectorTerms` could be removed after creation because Kubernetes skips field-level transition rules when an optional field becomes absent. This silently widened the request to match any member cluster. - Add a spec-level CEL presence guard alongside the existing field-level immutability rule, and regenerate the ClusterClaim CRD. - Cover the regression with an envtest in the new test/apis/kubefleet.dev/placement/v1alpha1 suite. Fixes #810 --- .../placement/v1alpha1/clusterclaim_types.go | 1 + ...placement.kubefleet.dev_clusterclaims.yaml | 4 + ...lusterclaim_validation_integration_test.go | 55 +++++++++ .../placement/v1alpha1/suite_test.go | 104 ++++++++++++++++++ 4 files changed, 164 insertions(+) create mode 100644 test/apis/kubefleet.dev/placement/v1alpha1/clusterclaim_validation_integration_test.go create mode 100644 test/apis/kubefleet.dev/placement/v1alpha1/suite_test.go diff --git a/apis/kubefleet.dev/placement/v1alpha1/clusterclaim_types.go b/apis/kubefleet.dev/placement/v1alpha1/clusterclaim_types.go index c9f3f9ab6..732e0aced 100644 --- a/apis/kubefleet.dev/placement/v1alpha1/clusterclaim_types.go +++ b/apis/kubefleet.dev/placement/v1alpha1/clusterclaim_types.go @@ -46,6 +46,7 @@ type ClusterClaim struct { Status ClusterClaimStatus `json:"status,omitempty"` } +// +kubebuilder:validation:XValidation:rule="has(self.clusterSelectorTerms) == has(oldSelf.clusterSelectorTerms)",message="the clusterSelectorTerms field cannot be added or removed after creation" type ClusterClaimSpec struct { // The reference to the placement policy that adds the cluster claim. // diff --git a/config/crd/bases/placement.kubefleet.dev_clusterclaims.yaml b/config/crd/bases/placement.kubefleet.dev_clusterclaims.yaml index 2bd4a6ad8..bb1fc81e0 100644 --- a/config/crd/bases/placement.kubefleet.dev_clusterclaims.yaml +++ b/config/crd/bases/placement.kubefleet.dev_clusterclaims.yaml @@ -220,6 +220,10 @@ spec: required: - placementPolicyRef type: object + x-kubernetes-validations: + - message: the clusterSelectorTerms field cannot be added or removed after + creation + rule: has(self.clusterSelectorTerms) == has(oldSelf.clusterSelectorTerms) status: description: The observed status of the cluster claim. properties: diff --git a/test/apis/kubefleet.dev/placement/v1alpha1/clusterclaim_validation_integration_test.go b/test/apis/kubefleet.dev/placement/v1alpha1/clusterclaim_validation_integration_test.go new file mode 100644 index 000000000..ee0df68c7 --- /dev/null +++ b/test/apis/kubefleet.dev/placement/v1alpha1/clusterclaim_validation_integration_test.go @@ -0,0 +1,55 @@ +/* +Copyright 2026 The KubeFleet Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/client" + + placementv1alpha1 "github.com/kubefleet-dev/kubefleet/apis/kubefleet.dev/placement/v1alpha1" +) + +var _ = Describe("Test ClusterClaim API validation", func() { + It("should deny unsetting clusterSelectorTerms", func() { + clusterClaim := &placementv1alpha1.ClusterClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "cluster-claim-selector-terms-immutability", + }, + Spec: placementv1alpha1.ClusterClaimSpec{ + PlacementPolicyRef: &placementv1alpha1.ObjectReference{ + Name: "test-placement-policy", + APIVersion: placementv1alpha1.GroupVersion.Version, + Kind: "PlacementPolicy", + }, + ClusterSelectorTerms: []placementv1alpha1.ClusterLabelAndPropertySelectorTerm{ + { + MatchLabels: map[string]string{"region": "west"}, + }, + }, + }, + } + Expect(hubClient.Create(ctx, clusterClaim)).Should(Succeed()) + DeferCleanup(func() { + Expect(client.IgnoreNotFound(hubClient.Delete(ctx, clusterClaim))).Should(Succeed()) + }) + + clusterClaim.Spec.ClusterSelectorTerms = nil + Expect(hubClient.Update(ctx, clusterClaim)).Should(MatchError(ContainSubstring("the clusterSelectorTerms field cannot be added or removed after creation"))) + }) +}) diff --git a/test/apis/kubefleet.dev/placement/v1alpha1/suite_test.go b/test/apis/kubefleet.dev/placement/v1alpha1/suite_test.go new file mode 100644 index 000000000..86250a777 --- /dev/null +++ b/test/apis/kubefleet.dev/placement/v1alpha1/suite_test.go @@ -0,0 +1,104 @@ +/* +Copyright 2025 The KubeFleet Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "context" + "flag" + "path/filepath" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/klog/v2" + "k8s.io/klog/v2/textlogger" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + + placementv1alpha1 "github.com/kubefleet-dev/kubefleet/apis/kubefleet.dev/placement/v1alpha1" +) + +var ( + hubTestEnv *envtest.Environment + hubClient client.Client + ctx context.Context + cancel context.CancelFunc +) + +func TestAPIs(t *testing.T) { + RegisterFailHandler(Fail) + + RunSpecs(t, "Placement v1alpha1 API Validation Suite") +} + +var _ = BeforeSuite(func() { + By("Setup klog") + fs := flag.NewFlagSet("klog", flag.ContinueOnError) + klog.InitFlags(fs) + Expect(fs.Parse([]string{"--v", "5", "-add_dir_header", "true"})).Should(Succeed()) + + ctx, cancel = context.WithCancel(context.TODO()) + + By("bootstrap the test environment") + // Start the cluster. + hubTestEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{ + filepath.Join("..", "..", "..", "..", "..", "config", "crd", "bases"), + }, + ErrorIfCRDPathMissing: true, + } + hubCfg, err := hubTestEnv.Start() + Expect(err).NotTo(HaveOccurred()) + Expect(hubCfg).NotTo(BeNil()) + + Expect(placementv1alpha1.AddToScheme(scheme.Scheme)).Should(Succeed()) + + klog.InitFlags(flag.CommandLine) + flag.Parse() + // Create the hub controller manager. + hubCtrlMgr, err := ctrl.NewManager(hubCfg, ctrl.Options{ + Scheme: scheme.Scheme, + Metrics: metricsserver.Options{ + BindAddress: "0", + }, + Logger: textlogger.NewLogger(textlogger.NewConfig(textlogger.Verbosity(4))), + }) + Expect(err).NotTo(HaveOccurred()) + + // Set up the client. + // The client must be one with cache (i.e. configured by the controller manager) to make + // use of the cache indexes. + hubClient = hubCtrlMgr.GetClient() + Expect(hubClient).NotTo(BeNil()) + + go func() { + defer GinkgoRecover() + err = hubCtrlMgr.Start(ctx) + Expect(err).ToNot(HaveOccurred(), "failed to start manager for hub") + }() +}) + +var _ = AfterSuite(func() { + defer klog.Flush() + cancel() + + By("tearing down the test environment") + Expect(hubTestEnv.Stop()).Should(Succeed()) +}) From 053a86657dd6df76b0ea5c9d53abf607156df969 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 9 Sep 2026 10:43:49 -0700 Subject: [PATCH 07/10] fix: remediate 2026-W37 Trivy HIGH/CRITICAL CVEs in runtime images and deps (#887) * Initial plan * fix: remediate trivy CVEs from 2026-W37 Co-authored-by: britaniar <145056127+britaniar@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: britaniar <145056127+britaniar@users.noreply.github.com> --- apis/cluster/v1beta1/zz_generated.deepcopy.go | 2 +- .../v1alpha1/zz_generated.deepcopy.go | 2 +- .../v1alpha1/zz_generated.deepcopy.go | 2 +- .../v1beta1/zz_generated.deepcopy.go | 2 +- go.mod | 14 +++++----- go.sum | 28 +++++++++---------- test/apis/v1alpha1/zz_generated.deepcopy.go | 2 +- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/apis/cluster/v1beta1/zz_generated.deepcopy.go b/apis/cluster/v1beta1/zz_generated.deepcopy.go index a51641c3f..cec52aa39 100644 --- a/apis/cluster/v1beta1/zz_generated.deepcopy.go +++ b/apis/cluster/v1beta1/zz_generated.deepcopy.go @@ -21,7 +21,7 @@ limitations under the License. package v1beta1 import ( - "k8s.io/api/core/v1" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) diff --git a/apis/kubefleet.dev/placement/v1alpha1/zz_generated.deepcopy.go b/apis/kubefleet.dev/placement/v1alpha1/zz_generated.deepcopy.go index 8dac3f795..b483d46f4 100644 --- a/apis/kubefleet.dev/placement/v1alpha1/zz_generated.deepcopy.go +++ b/apis/kubefleet.dev/placement/v1alpha1/zz_generated.deepcopy.go @@ -21,7 +21,7 @@ limitations under the License. package v1alpha1 import ( - "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" ) diff --git a/apis/placement/v1alpha1/zz_generated.deepcopy.go b/apis/placement/v1alpha1/zz_generated.deepcopy.go index 6d1656d18..df9f5e6d7 100644 --- a/apis/placement/v1alpha1/zz_generated.deepcopy.go +++ b/apis/placement/v1alpha1/zz_generated.deepcopy.go @@ -22,7 +22,7 @@ package v1alpha1 import ( "github.com/kubefleet-dev/kubefleet/apis/placement/v1beta1" - "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" ) diff --git a/apis/placement/v1beta1/zz_generated.deepcopy.go b/apis/placement/v1beta1/zz_generated.deepcopy.go index 73d66c8fa..b9ff2e710 100644 --- a/apis/placement/v1beta1/zz_generated.deepcopy.go +++ b/apis/placement/v1beta1/zz_generated.deepcopy.go @@ -21,7 +21,7 @@ limitations under the License. package v1beta1 import ( - "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" ) diff --git a/go.mod b/go.mod index 1c2789c6c..5868fb0c4 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( go.goms.io/fleet-networking v0.3.3 go.uber.org/atomic v1.11.0 go.uber.org/zap v1.27.0 - golang.org/x/sync v0.21.0 + golang.org/x/sync v0.22.0 golang.org/x/time v0.11.0 gomodules.xyz/jsonpatch/v2 v2.4.0 k8s.io/api v0.34.1 @@ -109,14 +109,14 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.53.0 // indirect + golang.org/x/crypto v0.55.0 // indirect golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect - golang.org/x/net v0.56.0 // indirect + golang.org/x/net v0.57.0 // indirect golang.org/x/oauth2 v0.29.0 // indirect - golang.org/x/sys v0.46.0 // indirect - golang.org/x/term v0.44.0 // indirect - golang.org/x/text v0.39.0 // indirect - golang.org/x/tools v0.47.0 // indirect + golang.org/x/sys v0.47.0 // indirect + golang.org/x/term v0.45.0 // indirect + golang.org/x/text v0.41.0 // indirect + golang.org/x/tools v0.48.0 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index eb34b6ebf..cc40dc15d 100644 --- a/go.sum +++ b/go.sum @@ -326,8 +326,8 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= -golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= +golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= +golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -336,35 +336,35 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= -golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= +golang.org/x/net v0.57.0 h1:K5+3DljvIuDG9/Jv9rvyMywYNFCQ9RSUY6OOTTkT+tE= +golang.org/x/net v0.57.0/go.mod h1:KpXc8iv+r3XplLAG/f7Jsf9RPszJzdR0f58q9vGOuEU= golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98= golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= -golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= +golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= -golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= -golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= +golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= +golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0= +golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.39.0 h1:UbZz4pLOvn600D6Oh6GGEI6VAmndrEBLv8/6BEXzyus= -golang.org/x/text v0.39.0/go.mod h1:3UwRclnC2g0TU9x8PZiyfOajCd1zaUNHF9cvqcQZ+ZM= +golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= +golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= -golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= +golang.org/x/tools v0.48.0 h1:3+hClM1aLL5mjMKm5ovokw9epgRXPuu2tILgismM6RE= +golang.org/x/tools v0.48.0/go.mod h1:08xX0orndb/F7jJxGDicx061tyd5pcMto75YMAXr6lk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/test/apis/v1alpha1/zz_generated.deepcopy.go b/test/apis/v1alpha1/zz_generated.deepcopy.go index 081bec913..143bdee7b 100644 --- a/test/apis/v1alpha1/zz_generated.deepcopy.go +++ b/test/apis/v1alpha1/zz_generated.deepcopy.go @@ -21,7 +21,7 @@ limitations under the License. package v1alpha1 import ( - "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) From e6d864238ed2ca2262ec68c8cc014f8fc55be2b0 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 9 Sep 2026 16:49:50 -0700 Subject: [PATCH 08/10] chore: upgrade golang.org/x/crypto to v0.56.0 (#908) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: britaniar <145056127+britaniar@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5868fb0c4..f1ff912dc 100644 --- a/go.mod +++ b/go.mod @@ -109,7 +109,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.55.0 // indirect + golang.org/x/crypto v0.56.0 // indirect golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect golang.org/x/net v0.57.0 // indirect golang.org/x/oauth2 v0.29.0 // indirect diff --git a/go.sum b/go.sum index cc40dc15d..30fffd591 100644 --- a/go.sum +++ b/go.sum @@ -326,8 +326,8 @@ go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= -golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= +golang.org/x/crypto v0.56.0 h1:GUh5Ii4J5jtcseSMiRqr1jXCNHoxjeV9Fmekc2oLy6Y= +golang.org/x/crypto v0.56.0/go.mod h1:OMW5y6CY9l38uPLmxU6l6pwcXp1obtLo3e6gT7gQR2I= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw= golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= From 64d433016b53621b5eeb901af30e65ac9df89a99 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 11 Sep 2026 09:39:29 +1000 Subject: [PATCH 09/10] chore: bump github/codeql-action/init from 4.37.7 to 4.37.8 (#856) --- .github/workflows/codeql-analysis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 23b855f38..9651d240c 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -42,7 +42,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4 + uses: github/codeql-action/init@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -56,7 +56,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4 + uses: github/codeql-action/autobuild@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4 # â„šī¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -69,4 +69,4 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@ff2f1c621b7f889edc0d3c761ac2e6a3f8cdb0dd # v4 + uses: github/codeql-action/analyze@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4 From 248872a10934ed851b760aba2a22036dd6dd2fe2 Mon Sep 17 00:00:00 2001 From: Arvind Thirumurugan Date: Thu, 10 Sep 2026 20:34:17 -0700 Subject: [PATCH 10/10] rebase fix Signed-off-by: Arvind Thirumurugan --- .github/workflows/trivy.yml | 218 ------------------------------------ 1 file changed, 218 deletions(-) diff --git a/.github/workflows/trivy.yml b/.github/workflows/trivy.yml index a99635ea3..cb897bfc3 100644 --- a/.github/workflows/trivy.yml +++ b/.github/workflows/trivy.yml @@ -1,220 +1,3 @@ -<<<<<<< HEAD -name: Trivy Vulnerability Scanner -on: - schedule: - - cron: '0 6 * * *' # Daily at 6:00 AM UTC - push: - branches: - - main - # Publish semver tags as releases. - tags: - - 'v*.*.*' - workflow_dispatch: {} - -permissions: - contents: read - packages: write - issues: write - -env: - REGISTRY: ghcr.io - HUB_AGENT_IMAGE_NAME: hub-agent - MEMBER_AGENT_IMAGE_NAME: member-agent - REFRESH_TOKEN_IMAGE_NAME: refresh-token - - GO_VERSION: '1.26.6' - -jobs: - export-registry: - runs-on: ubuntu-latest - outputs: - registry: ${{ steps.export.outputs.registry }} - steps: - - id: export - run: | - # registry must be in lowercase - # store the images under dev - # TODO: need to cleanup dev images periodically - echo "registry=$(echo "${{ env.REGISTRY }}/${{ github.repository }}" | tr '[:upper:]' '[:lower:]')" >> "$GITHUB_OUTPUT" - scan-images: - needs: export-registry - env: - REGISTRY: ${{ needs.export-registry.outputs.registry }} - runs-on: ubuntu-latest - steps: - - name: Set up Go ${{ env.GO_VERSION }} - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7 - with: - go-version: ${{ env.GO_VERSION }} - - - name: Checkout code - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - name: Login to ${{ env.REGISTRY }} - uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: generate image version - run: echo "IMAGE_VERSION=$(git rev-parse --short=7 HEAD)" >> "$GITHUB_ENV" - - # Note: scheduled runs rebuild images to scan the latest code on main. - # This ensures we catch newly disclosed CVEs against the current source. - - name: Build and push images to registry with tag ${{ env.IMAGE_VERSION }} - run: | - make push - env: - REGISTRY: ${{ env.REGISTRY}} - TAG: ${{ env.IMAGE_VERSION }} - - - name: Scan ${{ env.REGISTRY }}/${{ env.HUB_AGENT_IMAGE_NAME }}:${{ env.IMAGE_VERSION }} - uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 - with: - image-ref: ${{ env.REGISTRY }}/${{ env.HUB_AGENT_IMAGE_NAME }}:${{ env.IMAGE_VERSION }} - format: 'json' - output: 'trivy-hub-agent.json' - ignore-unfixed: true - vuln-type: 'os,library' - severity: 'CRITICAL,HIGH' - timeout: '5m0s' - env: - TRIVY_USERNAME: ${{ github.actor }} - TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }} - TRIVY_DB_REPOSITORY: mcr.microsoft.com/oss/v2/aquasecurity/trivy-db - - - name: Scan ${{ env.REGISTRY }}/${{ env.MEMBER_AGENT_IMAGE_NAME }}:${{ env.IMAGE_VERSION }} - uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 - with: - image-ref: ${{ env.REGISTRY }}/${{ env.MEMBER_AGENT_IMAGE_NAME }}:${{ env.IMAGE_VERSION }} - format: 'json' - output: 'trivy-member-agent.json' - ignore-unfixed: true - vuln-type: 'os,library' - severity: 'CRITICAL,HIGH' - timeout: '5m0s' - env: - TRIVY_USERNAME: ${{ github.actor }} - TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }} - TRIVY_DB_REPOSITORY: mcr.microsoft.com/oss/v2/aquasecurity/trivy-db - - - name: Scan ${{ env.REGISTRY }}/${{ env.REFRESH_TOKEN_IMAGE_NAME }}:${{ env.IMAGE_VERSION }} - uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0 - with: - image-ref: ${{ env.REGISTRY }}/${{ env.REFRESH_TOKEN_IMAGE_NAME }}:${{ env.IMAGE_VERSION }} - format: 'json' - output: 'trivy-refresh-token.json' - ignore-unfixed: true - vuln-type: 'os,library' - severity: 'CRITICAL,HIGH' - timeout: '5m0s' - env: - TRIVY_USERNAME: ${{ github.actor }} - TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }} - TRIVY_DB_REPOSITORY: mcr.microsoft.com/oss/v2/aquasecurity/trivy-db - - - name: Check for vulnerabilities - id: check-vulns - run: | - has_vulns=false - for file in trivy-hub-agent.json trivy-member-agent.json trivy-refresh-token.json; do - count=$(jq '[.Results[]? | .Vulnerabilities[]?] | length' "$file") - if [ "$count" -gt 0 ]; then - has_vulns=true - break - fi - done - echo "has_vulns=$has_vulns" >> "$GITHUB_OUTPUT" - - - name: Fail on vulnerabilities (non-scheduled runs) - if: steps.check-vulns.outputs.has_vulns == 'true' && github.event_name != 'schedule' - run: | - echo "::error::Vulnerabilities found. See trivy scan output." - for file in trivy-hub-agent.json trivy-member-agent.json trivy-refresh-token.json; do - echo "--- $file ---" - jq -r '.Results[]? | .Vulnerabilities[]? | "\(.VulnerabilityID) \(.Severity) \(.PkgName) \(.InstalledVersion) -> \(.FixedVersion)"' "$file" - done - exit 1 - - - name: Build vulnerability summary - if: steps.check-vulns.outputs.has_vulns == 'true' && github.event_name == 'schedule' - id: vuln-summary - run: | - { - echo 'body<@\`" - echo "2. Run \`go mod tidy\` to clean up dependencies." - echo "" - echo "**OS / base-image CVEs:**" - echo "1. Update the base image in the relevant \`Dockerfile\` under \`docker/\`." - echo "" - echo "**Then verify:**" - echo "1. Run \`make build\` to verify the build passes." - echo "2. Run \`make test\` to verify tests pass." - echo "" - echo "**Review:** Request review from \`@kubefleet-dev/kubefleet-secops\` on the resulting PR." - echo 'EOF' - } >> "$GITHUB_OUTPUT" - - - name: Create or update security issue - if: steps.check-vulns.outputs.has_vulns == 'true' && github.event_name == 'schedule' - uses: actions/github-script@v9 - with: - script: | - const today = new Date().toISOString().split('T')[0]; - const title = `fix: address trivy CVEs found on ${today}`; - const securityTeam = '@kubefleet-dev/kubefleet-secops'; - const body = `${process.env.ISSUE_BODY}\n\n### Security owners\n${securityTeam}`; - - // Check if an open issue already exists for today - const existing = await github.rest.issues.listForRepo({ - owner: context.repo.owner, - repo: context.repo.repo, - state: 'open', - labels: 'security,trivy', - per_page: 100 - }); - const issue = existing.data.find(i => i.title === title); - if (issue) { - await github.rest.issues.update({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - body: body - }); - console.log('Updated the existing issue with the current scan and security team mention.'); - } else { - await github.rest.issues.create({ - owner: context.repo.owner, - repo: context.repo.repo, - title: title, - body: body, - labels: ['security', 'trivy'] - }); - } - env: - ISSUE_BODY: ${{ steps.vuln-summary.outputs.body }} -======= name: Trivy Vulnerability Scanner on: schedule: @@ -467,4 +250,3 @@ jobs: } env: ISSUE_BODY: ${{ steps.vuln-summary.outputs.body }} ->>>>>>> cncf/main