From 44b4cc62e5c840b80b2cf55ee35e9c9df0dda2ad Mon Sep 17 00:00:00 2001 From: Cody Soyland Date: Thu, 31 Oct 2024 13:20:24 -0400 Subject: [PATCH 1/7] Add check for ACR registry in ACR credential helper (#1658) Signed-off-by: Cody Soyland Signed-off-by: Senan Zedan (EXT-Nokia) --- pkg/webhook/registryauth/azure/acrhelper.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pkg/webhook/registryauth/azure/acrhelper.go b/pkg/webhook/registryauth/azure/acrhelper.go index 87b996519..c7054c6e0 100644 --- a/pkg/webhook/registryauth/azure/acrhelper.go +++ b/pkg/webhook/registryauth/azure/acrhelper.go @@ -20,6 +20,7 @@ import ( "fmt" "net/url" "os" + "strings" "github.com/Azure/azure-sdk-for-go/profiles/preview/preview/containerregistry/runtime/containerregistry" "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" @@ -42,6 +43,10 @@ func (a ACRHelper) Delete(_ string) error { } func (a ACRHelper) Get(registryURL string) (string, string, error) { + if !isACR(registryURL) { + return "", "", fmt.Errorf("not an ACR registry") + } + azCred, err := azidentity.NewDefaultAzureCredential(nil) if err != nil { return "", "", fmt.Errorf("failed to obtain a credential: %w", err) @@ -81,3 +86,7 @@ func (a ACRHelper) Get(registryURL string) (string, string, error) { func (a ACRHelper) List() (map[string]string, error) { return nil, fmt.Errorf("list is unimplemented") } + +func isACR(registryURL string) bool { + return strings.HasSuffix(registryURL, ".azurecr.io") +} From 7895e28ab67c00f83c6594620115c197cd4e08ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 17:20:44 +0000 Subject: [PATCH 2/7] chore(deps): Bump google-github-actions/auth from 2.1.6 to 2.1.7 (#1683) Bumps [google-github-actions/auth](https://github.com/google-github-actions/auth) from 2.1.6 to 2.1.7. - [Release notes](https://github.com/google-github-actions/auth/releases) - [Changelog](https://github.com/google-github-actions/auth/blob/main/CHANGELOG.md) - [Commits](https://github.com/google-github-actions/auth/compare/8254fb75a33b976a221574d287e93919e6a36f70...6fc4af4b145ae7821d527454aa9bd537d1f2dc5f) --- updated-dependencies: - dependency-name: google-github-actions/auth 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> Signed-off-by: Senan Zedan (EXT-Nokia) --- .github/workflows/build.yaml | 2 +- .github/workflows/release.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 80b3e1642..e174fde2e 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -48,7 +48,7 @@ jobs: - uses: chainguard-dev/actions/goimports@dacf41f3472c33979cfd49bca5b503236be57de0 # main - name: Set up Cloud SDK - uses: google-github-actions/auth@8254fb75a33b976a221574d287e93919e6a36f70 # v2.1.6 + uses: google-github-actions/auth@6fc4af4b145ae7821d527454aa9bd537d1f2dc5f # v2.1.7 with: workload_identity_provider: 'projects/498091336538/locations/global/workloadIdentityPools/githubactions/providers/sigstore-policy-controller' service_account: 'gha-policy-controller@projectsigstore.iam.gserviceaccount.com' diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d0816022a..f370fb0ee 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -42,7 +42,7 @@ jobs: - uses: ko-build/setup-ko@3aebd0597dc1e9d1a26bcfdb7cbeb19c131d3037 # v0.7 - name: Set up Cloud SDK - uses: google-github-actions/auth@8254fb75a33b976a221574d287e93919e6a36f70 # v2.1.6 + uses: google-github-actions/auth@6fc4af4b145ae7821d527454aa9bd537d1f2dc5f # v2.1.7 with: workload_identity_provider: 'projects/498091336538/locations/global/workloadIdentityPools/githubactions/providers/sigstore-policy-controller' service_account: 'gha-policy-controller@projectsigstore.iam.gserviceaccount.com' From 513fa0ccf41043051363bebbb2fc9e1669677024 Mon Sep 17 00:00:00 2001 From: "Senan Zedan (EXT-Nokia)" Date: Sun, 3 Nov 2024 14:46:27 +0200 Subject: [PATCH 3/7] Control the policy controller monitoring resources from chart, enhancment for the current implmentation to hadd all the resources by default, The new change add avail to pass resourcesNames through the chart with list of resources comma sperataed for which resources to be monitored by the policy controller, the default is all resources if the flag wasn't presented in the chart Signed-off-by: Senan Zedan (EXT-Nokia) --- cmd/webhook/main.go | 50 ++++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/cmd/webhook/main.go b/cmd/webhook/main.go index 52f329caa..6e583e2ab 100644 --- a/cmd/webhook/main.go +++ b/cmd/webhook/main.go @@ -21,6 +21,7 @@ import ( "fmt" "log" "os" + "strings" "time" policyduckv1beta1 "github.com/sigstore/policy-controller/pkg/apis/duck/v1beta1" @@ -78,6 +79,13 @@ var ( // https://github.com/sigstore/policy-controller/issues/354 disableTUF = flag.Bool("disable-tuf", false, "Disable TUF support.") + // Validate specific resources. + // https://github.com/sigstore/policy-controller/issues/1388 + resourcesNames = flag.String("resource-name", "replicasets, deployments, pods, cronjobs, jobs, statefulsets, daemonsets", "Comma-separated list of resources") + // Split the input string into a slice of strings + listResources []string + types map[schema.GroupVersionKind]resourcesemantics.GenericCRD + // mutatingCIPWebhookName holds the name of the mutating webhook configuration // resource dispatching admission requests to policy-webhook. // It is also the name of the webhook which is injected by the controller @@ -116,6 +124,8 @@ func main() { flag.IntVar(&opts.Port, "secure-port", opts.Port, "The port on which to serve HTTPS.") flag.Parse() + resourcesNamesList := strings.Split(*resourcesNames, ",") + listResources = append(listResources, resourcesNamesList...) // If TUF has been disabled do not try to set it up. if !*disableTUF { @@ -140,8 +150,7 @@ func main() { // This must match the set of resources we configure in // cmd/webhook/main.go in the "types" map. - common.ValidResourceNames = sets.NewString("replicasets", "deployments", - "pods", "cronjobs", "jobs", "statefulsets", "daemonsets") + common.ValidResourceNames = sets.NewString(resourcesNamesList...) v := version.GetVersionInfo() vJSON, _ := v.JSONString() @@ -198,17 +207,29 @@ func (c *crdEphemeralContainers) SupportedVerbs() []admissionregistrationv1.Oper } } -var types = map[schema.GroupVersionKind]resourcesemantics.GenericCRD{ - corev1.SchemeGroupVersion.WithKind("Pod"): &crdEphemeralContainers{GenericCRD: &duckv1.Pod{}}, - - appsv1.SchemeGroupVersion.WithKind("ReplicaSet"): &crdNoStatusUpdatesOrDeletes{GenericCRD: &policyduckv1beta1.PodScalable{}}, - appsv1.SchemeGroupVersion.WithKind("Deployment"): &crdNoStatusUpdatesOrDeletes{GenericCRD: &policyduckv1beta1.PodScalable{}}, - appsv1.SchemeGroupVersion.WithKind("StatefulSet"): &crdNoStatusUpdatesOrDeletes{GenericCRD: &policyduckv1beta1.PodScalable{}}, - appsv1.SchemeGroupVersion.WithKind("DaemonSet"): &crdNoStatusUpdatesOrDeletes{GenericCRD: &duckv1.WithPod{}}, - batchv1.SchemeGroupVersion.WithKind("Job"): &crdNoStatusUpdatesOrDeletes{GenericCRD: &duckv1.WithPod{}}, - - batchv1.SchemeGroupVersion.WithKind("CronJob"): &crdNoStatusUpdatesOrDeletes{GenericCRD: &duckv1.CronJob{}}, - batchv1beta1.SchemeGroupVersion.WithKind("CronJob"): &crdNoStatusUpdatesOrDeletes{GenericCRD: &duckv1.CronJob{}}, +func createTypesMap(kindsList []string) map[schema.GroupVersionKind]resourcesemantics.GenericCRD { + types := make(map[schema.GroupVersionKind]resourcesemantics.GenericCRD) + for _, kind := range kindsList { + kind = strings.TrimSpace(kind) + switch kind { + case "pods": + types[corev1.SchemeGroupVersion.WithKind("Pod")] = &crdEphemeralContainers{GenericCRD: &duckv1.Pod{}} + case "replicasets": + types[appsv1.SchemeGroupVersion.WithKind("ReplicaSet")] = &crdNoStatusUpdatesOrDeletes{GenericCRD: &policyduckv1beta1.PodScalable{}} + case "deployments": + types[appsv1.SchemeGroupVersion.WithKind("Deployment")] = &crdNoStatusUpdatesOrDeletes{GenericCRD: &policyduckv1beta1.PodScalable{}} + case "statefulsets": + types[appsv1.SchemeGroupVersion.WithKind("StatefulSet")] = &crdNoStatusUpdatesOrDeletes{GenericCRD: &policyduckv1beta1.PodScalable{}} + case "daemonsets": + types[appsv1.SchemeGroupVersion.WithKind("DaemonSet")] = &crdNoStatusUpdatesOrDeletes{GenericCRD: &duckv1.WithPod{}} + case "jobs": + types[batchv1.SchemeGroupVersion.WithKind("Job")] = &crdNoStatusUpdatesOrDeletes{GenericCRD: &duckv1.WithPod{}} + case "cronjobs": + types[batchv1.SchemeGroupVersion.WithKind("CronJob")] = &crdNoStatusUpdatesOrDeletes{GenericCRD: &duckv1.CronJob{}} + types[batchv1beta1.SchemeGroupVersion.WithKind("CronJob")] = &crdNoStatusUpdatesOrDeletes{GenericCRD: &duckv1.CronJob{}} + } + } + return types } var typesCIP = map[schema.GroupVersionKind]resourcesemantics.GenericCRD{ @@ -221,6 +242,7 @@ var typesCIP = map[schema.GroupVersionKind]resourcesemantics.GenericCRD{ func NewValidatingAdmissionController(ctx context.Context, cmw configmap.Watcher) *controller.Impl { // Decorate contexts with the current state of the config. + types = createTypesMap(listResources) store := config.NewStore(logging.FromContext(ctx).Named("config-store")) store.WatchConfigs(cmw) policyControllerConfigStore := policycontrollerconfig.NewStore(logging.FromContext(ctx).Named("config-policy-controller")) @@ -278,7 +300,7 @@ func NewMutatingAdmissionController(ctx context.Context, _ configmap.Watcher) *c } ctx = webhook.WithOptions(ctx, *woptions) validator := cwebhook.NewValidator(ctx) - + types = createTypesMap(listResources) return defaulting.NewAdmissionController(ctx, // Name of the resource webhook. *webhookName, From 8bf379c67057bed49123ecc29f235fc9ca5851f5 Mon Sep 17 00:00:00 2001 From: "Senan Zedan (EXT-Nokia)" Date: Thu, 12 Dec 2024 14:36:16 +0200 Subject: [PATCH 4/7] --amend --- .../kind-cluster-custom-resources.yaml | 34 +---------- test/e2e_test_policy_custom_resource.sh | 58 +++++++++++++++++-- .../kustomization.yaml | 5 +- .../test-deployment-with-custom-resource.yaml | 12 ++-- 4 files changed, 60 insertions(+), 49 deletions(-) diff --git a/.github/workflows/kind-cluster-custom-resources.yaml b/.github/workflows/kind-cluster-custom-resources.yaml index bdaa33d15..dcdfd59c6 100644 --- a/.github/workflows/kind-cluster-custom-resources.yaml +++ b/.github/workflows/kind-cluster-custom-resources.yaml @@ -26,7 +26,7 @@ permissions: read-all jobs: cip-test-trustroot-bring-your-own-keys: - name: ClusterImagePolicy e2e tests with TrustRoot - Bring Your Own Keys + name: ClusterImagePolicy e2e tests with custom resources runs-on: ubuntu-latest strategy: @@ -138,38 +138,6 @@ jobs: kubectl rollout status --timeout 5m --namespace cosign-system deployments/webhook echo "TUF_ROOT_FILE=./root.json" >> $GITHUB_ENV - - name: Checkout TSA for testing. - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v3.0.2 - with: - repository: sigstore/timestamp-authority - path: ./src/github.com/sigstore/timestamp-authority - - - name: Build timestamp-cli - working-directory: ./src/github.com/sigstore/timestamp-authority - run: | - go build -o ./timestamp-cli ./cmd/timestamp-cli - - - name: Exercise our local TSA - working-directory: ./src/github.com/sigstore/timestamp-authority - run: | - TSA_URL=$(kubectl -n tsa-system get ksvc tsa -ojsonpath='{.status.url}') - echo "TSA_URL=$TSA_URL" >> $GITHUB_ENV - - curl $TSA_URL/api/v1/timestamp/certchain > ts_chain.pem - echo "myblob" > myblob - if ! ./timestamp-cli --timestamp_server $TSA_URL timestamp --hash sha256 --artifact myblob --out response.tsr ; then - echo "failed to timestamp artifact" - exit -1 - fi - if ! ./timestamp-cli verify --timestamp response.tsr --artifact "myblob" --certificate-chain ts_chain.pem ; then - echo "failed to verify timestamp" - exit -1 - fi - if ! ./timestamp-cli inspect --timestamp response.tsr --format json ; then - echo "failed to inspect the timestamp" - exit -1 - fi - - name: Run Custom resources Tests timeout-minutes: 5 run: | diff --git a/test/e2e_test_policy_custom_resource.sh b/test/e2e_test_policy_custom_resource.sh index 457abb93b..f2d608210 100644 --- a/test/e2e_test_policy_custom_resource.sh +++ b/test/e2e_test_policy_custom_resource.sh @@ -22,7 +22,7 @@ if [[ -z "${KO_DOCKER_REPO}" ]]; then fi # Variables -export CUSTOM_RESOURCE="Pods,ReplicaSets" +export CUSTOM_RESOURCE="DaemonSet,ReplicaSets" export NS=custom-resource-test export TIMESTAMP="TIMESTAMP" @@ -39,30 +39,76 @@ assert_webhook_configuration() { echo "Resource ${resource} found in ${webhook_name}" } +# Helper function to check if an image uses a tag +assert_image_tag() { + local pod_name=$1 + local container_name=$2 + + echo "Checking that ${pod_name}/${container_name} uses a tag, not a digest" + image=$(kubectl get pod "${pod_name}" -n "${NS}" -o=jsonpath="{.spec.containers[?(@.name=='${container_name}')].image}") + if [[ "${image}" =~ @sha256:[a-f0-9]{64} ]]; then + echo "Image ${image} is using a digest, which is not allowed" + exit 1 + else + echo "Image ${image} is correctly using a tag" + fi +} + +# Step 1: Create namespace echo '::group:: Create and label namespace for testing' kubectl create namespace ${NS} kubectl label namespace ${NS} policy.sigstore.dev/include=true echo '::endgroup::' +# Step 2: Deploy Policy Controller with custom-resource flag +echo '::group:: Deploy Policy Controller with custom-resource flag' +KO_DOCKER_REPO=${KO_DOCKER_REPO} ko apply -f ./deploy/manifests.yaml \ + --set-string policyController.customResource=${CUSTOM_RESOURCE} +echo '::endgroup::' + +# Step 3: Validate webhook configurations echo '::group:: Validate webhook configurations' sleep 5 # Allow webhook configurations to propagate -for resource in Pods ReplicaSets; do +for resource in DaemonSet ReplicaSets; do assert_webhook_configuration "MutatingWebhookConfiguration" "${resource}" assert_webhook_configuration "ValidatingWebhookConfiguration" "${resource}" done # Ensure a non-monitored resource is NOT included -if kubectl get MutatingWebhookConfiguration -o yaml | grep -q "resources:.*DaemonSet"; then - echo "DaemonSet should not be included in MutatingWebhookConfiguration" +if kubectl get MutatingWebhookConfiguration -o yaml | grep -q "resources:.*Pods"; then + echo "Pods should not be included in MutatingWebhookConfiguration" exit 1 else - echo "DaemonSet correctly excluded from MutatingWebhookConfiguration" + echo "Pods correctly excluded from MutatingWebhookConfiguration" fi echo '::endgroup::' +# Step 4: Deploy sandbox and check for image tag usage +echo '::group:: Deploy sandbox and check image tags' +cat < Date: Sun, 3 Nov 2024 14:46:27 +0200 Subject: [PATCH 5/7] Control the policy controller monitoring resources from chart, enhancment for the current implmentation to hadd all the resources by default, The new change add avail to pass resourcesNames through the chart with list of resources comma sperataed for which resources to be monitored by the policy controller, the default is all resources if the flag wasn't presented in the chart Signed-off-by: Senan Zedan (EXT-Nokia) --- cmd/webhook/main.go | 50 ++++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/cmd/webhook/main.go b/cmd/webhook/main.go index 52f329caa..6e583e2ab 100644 --- a/cmd/webhook/main.go +++ b/cmd/webhook/main.go @@ -21,6 +21,7 @@ import ( "fmt" "log" "os" + "strings" "time" policyduckv1beta1 "github.com/sigstore/policy-controller/pkg/apis/duck/v1beta1" @@ -78,6 +79,13 @@ var ( // https://github.com/sigstore/policy-controller/issues/354 disableTUF = flag.Bool("disable-tuf", false, "Disable TUF support.") + // Validate specific resources. + // https://github.com/sigstore/policy-controller/issues/1388 + resourcesNames = flag.String("resource-name", "replicasets, deployments, pods, cronjobs, jobs, statefulsets, daemonsets", "Comma-separated list of resources") + // Split the input string into a slice of strings + listResources []string + types map[schema.GroupVersionKind]resourcesemantics.GenericCRD + // mutatingCIPWebhookName holds the name of the mutating webhook configuration // resource dispatching admission requests to policy-webhook. // It is also the name of the webhook which is injected by the controller @@ -116,6 +124,8 @@ func main() { flag.IntVar(&opts.Port, "secure-port", opts.Port, "The port on which to serve HTTPS.") flag.Parse() + resourcesNamesList := strings.Split(*resourcesNames, ",") + listResources = append(listResources, resourcesNamesList...) // If TUF has been disabled do not try to set it up. if !*disableTUF { @@ -140,8 +150,7 @@ func main() { // This must match the set of resources we configure in // cmd/webhook/main.go in the "types" map. - common.ValidResourceNames = sets.NewString("replicasets", "deployments", - "pods", "cronjobs", "jobs", "statefulsets", "daemonsets") + common.ValidResourceNames = sets.NewString(resourcesNamesList...) v := version.GetVersionInfo() vJSON, _ := v.JSONString() @@ -198,17 +207,29 @@ func (c *crdEphemeralContainers) SupportedVerbs() []admissionregistrationv1.Oper } } -var types = map[schema.GroupVersionKind]resourcesemantics.GenericCRD{ - corev1.SchemeGroupVersion.WithKind("Pod"): &crdEphemeralContainers{GenericCRD: &duckv1.Pod{}}, - - appsv1.SchemeGroupVersion.WithKind("ReplicaSet"): &crdNoStatusUpdatesOrDeletes{GenericCRD: &policyduckv1beta1.PodScalable{}}, - appsv1.SchemeGroupVersion.WithKind("Deployment"): &crdNoStatusUpdatesOrDeletes{GenericCRD: &policyduckv1beta1.PodScalable{}}, - appsv1.SchemeGroupVersion.WithKind("StatefulSet"): &crdNoStatusUpdatesOrDeletes{GenericCRD: &policyduckv1beta1.PodScalable{}}, - appsv1.SchemeGroupVersion.WithKind("DaemonSet"): &crdNoStatusUpdatesOrDeletes{GenericCRD: &duckv1.WithPod{}}, - batchv1.SchemeGroupVersion.WithKind("Job"): &crdNoStatusUpdatesOrDeletes{GenericCRD: &duckv1.WithPod{}}, - - batchv1.SchemeGroupVersion.WithKind("CronJob"): &crdNoStatusUpdatesOrDeletes{GenericCRD: &duckv1.CronJob{}}, - batchv1beta1.SchemeGroupVersion.WithKind("CronJob"): &crdNoStatusUpdatesOrDeletes{GenericCRD: &duckv1.CronJob{}}, +func createTypesMap(kindsList []string) map[schema.GroupVersionKind]resourcesemantics.GenericCRD { + types := make(map[schema.GroupVersionKind]resourcesemantics.GenericCRD) + for _, kind := range kindsList { + kind = strings.TrimSpace(kind) + switch kind { + case "pods": + types[corev1.SchemeGroupVersion.WithKind("Pod")] = &crdEphemeralContainers{GenericCRD: &duckv1.Pod{}} + case "replicasets": + types[appsv1.SchemeGroupVersion.WithKind("ReplicaSet")] = &crdNoStatusUpdatesOrDeletes{GenericCRD: &policyduckv1beta1.PodScalable{}} + case "deployments": + types[appsv1.SchemeGroupVersion.WithKind("Deployment")] = &crdNoStatusUpdatesOrDeletes{GenericCRD: &policyduckv1beta1.PodScalable{}} + case "statefulsets": + types[appsv1.SchemeGroupVersion.WithKind("StatefulSet")] = &crdNoStatusUpdatesOrDeletes{GenericCRD: &policyduckv1beta1.PodScalable{}} + case "daemonsets": + types[appsv1.SchemeGroupVersion.WithKind("DaemonSet")] = &crdNoStatusUpdatesOrDeletes{GenericCRD: &duckv1.WithPod{}} + case "jobs": + types[batchv1.SchemeGroupVersion.WithKind("Job")] = &crdNoStatusUpdatesOrDeletes{GenericCRD: &duckv1.WithPod{}} + case "cronjobs": + types[batchv1.SchemeGroupVersion.WithKind("CronJob")] = &crdNoStatusUpdatesOrDeletes{GenericCRD: &duckv1.CronJob{}} + types[batchv1beta1.SchemeGroupVersion.WithKind("CronJob")] = &crdNoStatusUpdatesOrDeletes{GenericCRD: &duckv1.CronJob{}} + } + } + return types } var typesCIP = map[schema.GroupVersionKind]resourcesemantics.GenericCRD{ @@ -221,6 +242,7 @@ var typesCIP = map[schema.GroupVersionKind]resourcesemantics.GenericCRD{ func NewValidatingAdmissionController(ctx context.Context, cmw configmap.Watcher) *controller.Impl { // Decorate contexts with the current state of the config. + types = createTypesMap(listResources) store := config.NewStore(logging.FromContext(ctx).Named("config-store")) store.WatchConfigs(cmw) policyControllerConfigStore := policycontrollerconfig.NewStore(logging.FromContext(ctx).Named("config-policy-controller")) @@ -278,7 +300,7 @@ func NewMutatingAdmissionController(ctx context.Context, _ configmap.Watcher) *c } ctx = webhook.WithOptions(ctx, *woptions) validator := cwebhook.NewValidator(ctx) - + types = createTypesMap(listResources) return defaulting.NewAdmissionController(ctx, // Name of the resource webhook. *webhookName, From e3b82ef2d111a155a4b8231bb0bba94c892b3cc8 Mon Sep 17 00:00:00 2001 From: "Senan Zedan (EXT-Nokia)" Date: Thu, 12 Dec 2024 14:36:16 +0200 Subject: [PATCH 6/7] --amend --- .../kind-cluster-custom-resources.yaml | 148 ++++++++++++++++++ test/e2e_test_policy_custom_resource.sh | 114 ++++++++++++++ .../kustomization.yaml | 30 ++++ .../test-deployment-with-custom-resource.yaml | 36 +++++ 4 files changed, 328 insertions(+) create mode 100644 .github/workflows/kind-cluster-custom-resources.yaml create mode 100644 test/e2e_test_policy_custom_resource.sh create mode 100644 test/kustomize-custom-resource/kustomization.yaml create mode 100644 test/testdata/policy-controller/e2e/test-deployment-with-custom-resource.yaml diff --git a/.github/workflows/kind-cluster-custom-resources.yaml b/.github/workflows/kind-cluster-custom-resources.yaml new file mode 100644 index 000000000..dcdfd59c6 --- /dev/null +++ b/.github/workflows/kind-cluster-custom-resources.yaml @@ -0,0 +1,148 @@ +# Copyright 2022 The Sigstore 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. + +name: Test policy-controller with custom resource + +on: + pull_request: + branches: [ 'main', 'release-*' ] + +defaults: + run: + shell: bash + +permissions: read-all + +jobs: + cip-test-trustroot-bring-your-own-keys: + name: ClusterImagePolicy e2e tests with custom resources + runs-on: ubuntu-latest + + strategy: + fail-fast: false # Keep running if one leg fails. + matrix: + k8s-version: + - v1.27.x + - v1.28.x + - v1.29.x + + env: + KO_DOCKER_REPO: "registry.local:5000/policy-controller" + SCAFFOLDING_RELEASE_VERSION: "v0.7.2" + GO111MODULE: on + GOFLAGS: -ldflags=-s -ldflags=-w + KOCACHE: ~/ko + + steps: + - name: free up disk space for the release + run: | + rm -rf /usr/share/dotnet/ + rm -rf "$AGENT_TOOLSDIRECTORY" + rm -rf "/usr/local/share/boost" + rm -rf /opt/ghc + docker rmi $(docker image ls -aq) || true + swapoff /swapfile || true + rm -rf /swapfile /usr/share/dotnet /usr/local/lib/android /opt/ghc || true + apt purge aria2 ansible hhvm mono-devel azure-cli shellcheck rpm xorriso zsync \ + clang-6.0 lldb-6.0 lld-6.0 clang-format-6.0 clang-8 lldb-8 lld-8 clang-format-8 \ + clang-9 lldb-9 lld-9 clangd-9 clang-format-9 dotnet-sdk-3.0 dotnet-sdk-3.1=3.1.101-1 \ + esl-erlang firefox g++-8 g++-9 gfortran-8 gfortran-9 google-chrome-stable \ + google-cloud-sdk ghc-8.0.2 ghc-8.2.2 ghc-8.4.4 ghc-8.6.2 ghc-8.6.3 ghc-8.6.4 \ + ghc-8.6.5 ghc-8.8.1 ghc-8.8.2 ghc-8.8.3 ghc-8.10.1 cabal-install-2.0 cabal-install-2.2 \ + cabal-install-2.4 cabal-install-3.0 cabal-install-3.2 heroku imagemagick \ + libmagickcore-dev libmagickwand-dev libmagic-dev ant ant-optional kubectl \ + mercurial apt-transport-https mono-complete mysql-client libmysqlclient-dev \ + mysql-server mssql-tools unixodbc-dev yarn bazel chrpath libssl-dev libxft-dev \ + libfreetype6 libfreetype6-dev libfontconfig1 libfontconfig1-dev php7.1 php7.1-bcmath \ + php7.1-bz2 php7.1-cgi php7.1-cli php7.1-common php7.1-curl php7.1-dba php7.1-dev \ + php7.1-enchant php7.1-fpm php7.1-gd php7.1-gmp php7.1-imap php7.1-interbase php7.1-intl \ + php7.1-json php7.1-ldap php7.1-mbstring php7.1-mcrypt php7.1-mysql php7.1-odbc \ + php7.1-opcache php7.1-pgsql php7.1-phpdbg php7.1-pspell php7.1-readline php7.1-recode \ + php7.1-snmp php7.1-soap php7.1-sqlite3 php7.1-sybase php7.1-tidy php7.1-xml \ + php7.1-xmlrpc php7.1-xsl php7.1-zip php7.2 php7.2-bcmath php7.2-bz2 php7.2-cgi \ + php7.2-cli php7.2-common php7.2-curl php7.2-dba php7.2-dev php7.2-enchant php7.2-fpm \ + php7.2-gd php7.2-gmp php7.2-imap php7.2-interbase php7.2-intl php7.2-json php7.2-ldap \ + php7.2-mbstring php7.2-mysql php7.2-odbc php7.2-opcache php7.2-pgsql php7.2-phpdbg \ + php7.2-pspell php7.2-readline php7.2-recode php7.2-snmp php7.2-soap php7.2-sqlite3 \ + php7.2-sybase php7.2-tidy php7.2-xml php7.2-xmlrpc php7.2-xsl php7.2-zip php7.3 \ + php7.3-bcmath php7.3-bz2 php7.3-cgi php7.3-cli php7.3-common php7.3-curl php7.3-dba \ + php7.3-dev php7.3-enchant php7.3-fpm php7.3-gd php7.3-gmp php7.3-imap php7.3-interbase \ + php7.3-intl php7.3-json php7.3-ldap php7.3-mbstring php7.3-mysql php7.3-odbc \ + php7.3-opcache php7.3-pgsql php7.3-phpdbg php7.3-pspell php7.3-readline php7.3-recode \ + php7.3-snmp php7.3-soap php7.3-sqlite3 php7.3-sybase php7.3-tidy php7.3-xml \ + php7.3-xmlrpc php7.3-xsl php7.3-zip php7.4 php7.4-bcmath php7.4-bz2 php7.4-cgi \ + php7.4-cli php7.4-common php7.4-curl php7.4-dba php7.4-dev php7.4-enchant php7.4-fpm \ + php7.4-gd php7.4-gmp php7.4-imap php7.4-interbase php7.4-intl php7.4-json php7.4-ldap \ + php7.4-mbstring php7.4-mysql php7.4-odbc php7.4-opcache php7.4-pgsql php7.4-phpdbg \ + php7.4-pspell php7.4-readline php7.4-snmp php7.4-soap php7.4-sqlite3 php7.4-sybase \ + php7.4-tidy php7.4-xml php7.4-xmlrpc php7.4-xsl php7.4-zip php-amqp php-apcu \ + php-igbinary php-memcache php-memcached php-mongodb php-redis php-xdebug \ + php-zmq snmp pollinate libpq-dev postgresql-client powershell ruby-full \ + sphinxsearch subversion mongodb-org -yq >/dev/null 2>&1 || true + apt-get remove -y 'php.*' || true + apt-get autoremove -y >/dev/null 2>&1 || true + apt-get autoclean -y >/dev/null 2>&1 || true + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + with: + go-version-file: './go.mod' + check-latest: true + + # will use the latest release available for ko + - uses: ko-build/setup-ko@3aebd0597dc1e9d1a26bcfdb7cbeb19c131d3037 # v0.7 + + - uses: imranismail/setup-kustomize@2ba527d4d055ab63514ba50a99456fc35684947f # v2.1.0 + + - name: Install yq + uses: mikefarah/yq@bbdd97482f2d439126582a59689eb1c855944955 # v4.44.3 + + - name: Setup mirror + uses: chainguard-dev/actions/setup-mirror@main + with: + mirror: mirror.gcr.io + + - uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v2 + + - name: Install cluster + sigstore + uses: sigstore/scaffolding/actions/setup@main + env: + INSTALL_TSA: true + with: + k8s-version: ${{ matrix.k8s-version}} + version: ${{ env.SCAFFOLDING_RELEASE_VERSION }} + + - name: Install policy-controller-with-only-pod-resource + env: + GIT_HASH: ${{ github.sha }} + GIT_VERSION: ci + LDFLAGS: "" + POLICY_CONTROLLER_YAML: test/kustomize-custom-resource/policy-controller-e2e.yaml + KO_PREFIX: registry.local:5000/policy-controller + POLICY_CONTROLLER_ARCHS: linux/amd64 + run: | + make ko-policy-controller + kustomize build test/kustomize-custom-resource | kubectl apply -f - + + # Wait for the webhook to come up and become Ready + kubectl rollout status --timeout 5m --namespace cosign-system deployments/webhook + echo "TUF_ROOT_FILE=./root.json" >> $GITHUB_ENV + + - name: Run Custom resources Tests + timeout-minutes: 5 + run: | + ./test/e2e_test_policy_custom_resource.sh + + - name: Collect diagnostics + if: ${{ failure() }} + uses: chainguard-dev/actions/kind-diag@29fb6e979a0b3efc79748a17e8cec08d0594cbfd # main diff --git a/test/e2e_test_policy_custom_resource.sh b/test/e2e_test_policy_custom_resource.sh new file mode 100644 index 000000000..f2d608210 --- /dev/null +++ b/test/e2e_test_policy_custom_resource.sh @@ -0,0 +1,114 @@ +#!/usr/bin/env bash +# +# Copyright 2024 The Sigstore 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. + +set -ex + +if [[ -z "${KO_DOCKER_REPO}" ]]; then + echo "Must specify env variable KO_DOCKER_REPO" + exit 1 +fi + +# Variables +export CUSTOM_RESOURCE="DaemonSet,ReplicaSets" +export NS=custom-resource-test +export TIMESTAMP="TIMESTAMP" + +# Helper function to validate webhook configuration +assert_webhook_configuration() { + local webhook_name=$1 + local resource=$2 + + echo "Validating ${webhook_name} for resource ${resource}" + kubectl get ${webhook_name} -o yaml | grep -q "resources:.*${resource}" || { + echo "Resource ${resource} not found in ${webhook_name}" + exit 1 + } + echo "Resource ${resource} found in ${webhook_name}" +} + +# Helper function to check if an image uses a tag +assert_image_tag() { + local pod_name=$1 + local container_name=$2 + + echo "Checking that ${pod_name}/${container_name} uses a tag, not a digest" + image=$(kubectl get pod "${pod_name}" -n "${NS}" -o=jsonpath="{.spec.containers[?(@.name=='${container_name}')].image}") + if [[ "${image}" =~ @sha256:[a-f0-9]{64} ]]; then + echo "Image ${image} is using a digest, which is not allowed" + exit 1 + else + echo "Image ${image} is correctly using a tag" + fi +} + +# Step 1: Create namespace +echo '::group:: Create and label namespace for testing' +kubectl create namespace ${NS} +kubectl label namespace ${NS} policy.sigstore.dev/include=true +echo '::endgroup::' + +# Step 2: Deploy Policy Controller with custom-resource flag +echo '::group:: Deploy Policy Controller with custom-resource flag' +KO_DOCKER_REPO=${KO_DOCKER_REPO} ko apply -f ./deploy/manifests.yaml \ + --set-string policyController.customResource=${CUSTOM_RESOURCE} +echo '::endgroup::' + +# Step 3: Validate webhook configurations +echo '::group:: Validate webhook configurations' +sleep 5 # Allow webhook configurations to propagate + +for resource in DaemonSet ReplicaSets; do + assert_webhook_configuration "MutatingWebhookConfiguration" "${resource}" + assert_webhook_configuration "ValidatingWebhookConfiguration" "${resource}" +done + +# Ensure a non-monitored resource is NOT included +if kubectl get MutatingWebhookConfiguration -o yaml | grep -q "resources:.*Pods"; then + echo "Pods should not be included in MutatingWebhookConfiguration" + exit 1 +else + echo "Pods correctly excluded from MutatingWebhookConfiguration" +fi +echo '::endgroup::' + +# Step 4: Deploy sandbox and check for image tag usage +echo '::group:: Deploy sandbox and check image tags' +cat < Date: Fri, 3 Jan 2025 13:25:07 +0200 Subject: [PATCH 7/7] Fix the formatting of the files and change misleading test name --- .../kind-cluster-custom-resources.yaml | 7 +++--- cmd/webhook/main.go | 14 +++++------ .../github.com/hashicorp/go-cleanhttp/doc.go | 1 - .../go-secure-stdlib/strutil/strutil.go | 10 ++++---- .../hashicorp/go-sockaddr/ifaddr.go | 12 +++++----- .../hashicorp/go-sockaddr/ifaddrs.go | 4 ++-- .../hashicorp/go-sockaddr/ipv4addr.go | 24 +++++++++---------- .../hashicorp/go-sockaddr/ipv6addr.go | 24 +++++++++---------- .../hashicorp/hcl/hcl/printer/nodes.go | 7 +++--- 9 files changed, 51 insertions(+), 52 deletions(-) diff --git a/.github/workflows/kind-cluster-custom-resources.yaml b/.github/workflows/kind-cluster-custom-resources.yaml index dcdfd59c6..ca660b68d 100644 --- a/.github/workflows/kind-cluster-custom-resources.yaml +++ b/.github/workflows/kind-cluster-custom-resources.yaml @@ -16,7 +16,7 @@ name: Test policy-controller with custom resource on: pull_request: - branches: [ 'main', 'release-*' ] + branches: ["main", "release-*"] defaults: run: @@ -96,7 +96,7 @@ jobs: - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: - go-version-file: './go.mod' + go-version-file: "./go.mod" check-latest: true # will use the latest release available for ko @@ -122,7 +122,7 @@ jobs: k8s-version: ${{ matrix.k8s-version}} version: ${{ env.SCAFFOLDING_RELEASE_VERSION }} - - name: Install policy-controller-with-only-pod-resource + - name: Install policy-controller-with-replicasets-daemonsets-resource env: GIT_HASH: ${{ github.sha }} GIT_VERSION: ci @@ -141,6 +141,7 @@ jobs: - name: Run Custom resources Tests timeout-minutes: 5 run: | + chmod +x ./test/e2e_test_policy_custom_resource.sh ./test/e2e_test_policy_custom_resource.sh - name: Collect diagnostics diff --git a/cmd/webhook/main.go b/cmd/webhook/main.go index 6e583e2ab..9ab58975a 100644 --- a/cmd/webhook/main.go +++ b/cmd/webhook/main.go @@ -80,11 +80,11 @@ var ( disableTUF = flag.Bool("disable-tuf", false, "Disable TUF support.") // Validate specific resources. - // https://github.com/sigstore/policy-controller/issues/1388 - resourcesNames = flag.String("resource-name", "replicasets, deployments, pods, cronjobs, jobs, statefulsets, daemonsets", "Comma-separated list of resources") - // Split the input string into a slice of strings - listResources []string - types map[schema.GroupVersionKind]resourcesemantics.GenericCRD + // https://github.com/sigstore/policy-controller/issues/1388 + resourcesNames = flag.String("resource-name", "replicasets, deployments, pods, cronjobs, jobs, statefulsets, daemonsets", "Comma-separated list of resources") + // Split the input string into a slice of strings + listResources []string + types map[schema.GroupVersionKind]resourcesemantics.GenericCRD // mutatingCIPWebhookName holds the name of the mutating webhook configuration // resource dispatching admission requests to policy-webhook. @@ -125,7 +125,7 @@ func main() { flag.Parse() resourcesNamesList := strings.Split(*resourcesNames, ",") - listResources = append(listResources, resourcesNamesList...) + listResources = append(listResources, resourcesNamesList...) // If TUF has been disabled do not try to set it up. if !*disableTUF { @@ -300,7 +300,7 @@ func NewMutatingAdmissionController(ctx context.Context, _ configmap.Watcher) *c } ctx = webhook.WithOptions(ctx, *woptions) validator := cwebhook.NewValidator(ctx) - types = createTypesMap(listResources) + types = createTypesMap(listResources) return defaulting.NewAdmissionController(ctx, // Name of the resource webhook. *webhookName, diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/go-cleanhttp/doc.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/go-cleanhttp/doc.go index 05841092a..905859c7f 100644 --- a/third_party/VENDOR-LICENSE/github.com/hashicorp/go-cleanhttp/doc.go +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/go-cleanhttp/doc.go @@ -16,5 +16,4 @@ // connecting to the same hosts repeatedly from the same client, you can use // DefaultPooledClient to receive a client that has connection pooling // semantics similar to http.DefaultClient. -// package cleanhttp diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/go-secure-stdlib/strutil/strutil.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/go-secure-stdlib/strutil/strutil.go index 102462dc6..b342b5062 100644 --- a/third_party/VENDOR-LICENSE/github.com/hashicorp/go-secure-stdlib/strutil/strutil.go +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/go-secure-stdlib/strutil/strutil.go @@ -110,11 +110,11 @@ func ParseKeyValues(input string, out map[string]string, sep string) error { // ParseArbitraryKeyValues parses arbitrary tuples. The input // can be one of the following: -// * JSON string -// * Base64 encoded JSON string -// * Comma separated list of `=` pairs -// * Base64 encoded string containing comma separated list of -// `=` pairs +// - JSON string +// - Base64 encoded JSON string +// - Comma separated list of `=` pairs +// - Base64 encoded string containing comma separated list of +// `=` pairs // // Input will be parsed into the output parameter, which should // be a non-nil map[string]string. diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ifaddr.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ifaddr.go index 0811b2759..277678871 100644 --- a/third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ifaddr.go +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ifaddr.go @@ -17,7 +17,7 @@ func init() { // // ``` // $ sockaddr eval -r '{{GetPrivateInterfaces | attr "address"}}' -/// ``` +// / ``` func GetPrivateIP() (string, error) { privateIfs, err := GetPrivateInterfaces() if err != nil { @@ -39,7 +39,7 @@ func GetPrivateIP() (string, error) { // // ``` // $ sockaddr eval -r '{{GetAllInterfaces | include "RFC" "6890" | join "address" " "}}' -/// ``` +// / ``` func GetPrivateIPs() (string, error) { ifAddrs, err := GetAllInterfaces() if err != nil { @@ -86,7 +86,7 @@ func GetPrivateIPs() (string, error) { // // ``` // $ sockaddr eval -r '{{GetPublicInterfaces | attr "address"}}' -/// ``` +// / ``` func GetPublicIP() (string, error) { publicIfs, err := GetPublicInterfaces() if err != nil { @@ -108,7 +108,7 @@ func GetPublicIP() (string, error) { // // ``` // $ sockaddr eval -r '{{GetAllInterfaces | exclude "RFC" "6890" | join "address" " "}}' -/// ``` +// / ``` func GetPublicIPs() (string, error) { ifAddrs, err := GetAllInterfaces() if err != nil { @@ -147,7 +147,7 @@ func GetPublicIPs() (string, error) { // // ``` // $ sockaddr eval -r '{{GetAllInterfaces | include "name" <> | sort "type,size" | include "flag" "forwardable" | attr "address" }}' -/// ``` +// / ``` func GetInterfaceIP(namedIfRE string) (string, error) { ifAddrs, err := GetAllInterfaces() if err != nil { @@ -188,7 +188,7 @@ func GetInterfaceIP(namedIfRE string) (string, error) { // // ``` // $ sockaddr eval -r '{{GetAllInterfaces | include "name" <> | sort "type,size" | join "address" " "}}' -/// ``` +// / ``` func GetInterfaceIPs(namedIfRE string) (string, error) { ifAddrs, err := GetAllInterfaces() if err != nil { diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ifaddrs.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ifaddrs.go index d2713afbf..8f51fc1b3 100644 --- a/third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ifaddrs.go +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ifaddrs.go @@ -303,7 +303,7 @@ func GetDefaultInterfaces() (IfAddrs, error) { // // ``` // $ sockaddr eval -r '{{GetAllInterfaces | include "type" "ip" | include "flags" "forwardable" | include "flags" "up" | sort "default,type,size" | include "RFC" "6890" }}' -/// ``` +// / ``` func GetPrivateInterfaces() (IfAddrs, error) { privateIfs, err := GetAllInterfaces() if err != nil { @@ -351,7 +351,7 @@ func GetPrivateInterfaces() (IfAddrs, error) { // // ``` // $ sockaddr eval -r '{{GetAllInterfaces | include "type" "ip" | include "flags" "forwardable" | include "flags" "up" | sort "default,type,size" | exclude "RFC" "6890" }}' -/// ``` +// / ``` func GetPublicInterfaces() (IfAddrs, error) { publicIfs, err := GetAllInterfaces() if err != nil { diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ipv4addr.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ipv4addr.go index 4d395dc95..356eb8563 100644 --- a/third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ipv4addr.go +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ipv4addr.go @@ -165,10 +165,10 @@ func (ipv4 IPv4Addr) BroadcastAddress() IPv4Network { // CmpAddress follows the Cmp() standard protocol and returns: // -// - -1 If the receiver should sort first because its address is lower than arg -// - 0 if the SockAddr arg is equal to the receiving IPv4Addr or the argument is -// of a different type. -// - 1 If the argument should sort first. +// - -1 If the receiver should sort first because its address is lower than arg +// - 0 if the SockAddr arg is equal to the receiving IPv4Addr or the argument is +// of a different type. +// - 1 If the argument should sort first. func (ipv4 IPv4Addr) CmpAddress(sa SockAddr) int { ipv4b, ok := sa.(IPv4Addr) if !ok { @@ -187,10 +187,10 @@ func (ipv4 IPv4Addr) CmpAddress(sa SockAddr) int { // CmpPort follows the Cmp() standard protocol and returns: // -// - -1 If the receiver should sort first because its port is lower than arg -// - 0 if the SockAddr arg's port number is equal to the receiving IPv4Addr, -// regardless of type. -// - 1 If the argument should sort first. +// - -1 If the receiver should sort first because its port is lower than arg +// - 0 if the SockAddr arg's port number is equal to the receiving IPv4Addr, +// regardless of type. +// - 1 If the argument should sort first. func (ipv4 IPv4Addr) CmpPort(sa SockAddr) int { var saPort IPPort switch v := sa.(type) { @@ -214,10 +214,10 @@ func (ipv4 IPv4Addr) CmpPort(sa SockAddr) int { // CmpRFC follows the Cmp() standard protocol and returns: // -// - -1 If the receiver should sort first because it belongs to the RFC and its -// arg does not -// - 0 if the receiver and arg both belong to the same RFC or neither do. -// - 1 If the arg belongs to the RFC but receiver does not. +// - -1 If the receiver should sort first because it belongs to the RFC and its +// arg does not +// - 0 if the receiver and arg both belong to the same RFC or neither do. +// - 1 If the arg belongs to the RFC but receiver does not. func (ipv4 IPv4Addr) CmpRFC(rfcNum uint, sa SockAddr) int { recvInRFC := IsRFC(rfcNum, ipv4) ipv4b, ok := sa.(IPv4Addr) diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ipv6addr.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ipv6addr.go index d7f412111..bd49fb7a0 100644 --- a/third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ipv6addr.go +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ipv6addr.go @@ -173,10 +173,10 @@ func (ipv6 IPv6Addr) AddressHexString() string { // CmpAddress follows the Cmp() standard protocol and returns: // -// - -1 If the receiver should sort first because its address is lower than arg -// - 0 if the SockAddr arg equal to the receiving IPv6Addr or the argument is of a -// different type. -// - 1 If the argument should sort first. +// - -1 If the receiver should sort first because its address is lower than arg +// - 0 if the SockAddr arg equal to the receiving IPv6Addr or the argument is of a +// different type. +// - 1 If the argument should sort first. func (ipv6 IPv6Addr) CmpAddress(sa SockAddr) int { ipv6b, ok := sa.(IPv6Addr) if !ok { @@ -193,10 +193,10 @@ func (ipv6 IPv6Addr) CmpAddress(sa SockAddr) int { // CmpPort follows the Cmp() standard protocol and returns: // -// - -1 If the receiver should sort first because its port is lower than arg -// - 0 if the SockAddr arg's port number is equal to the receiving IPv6Addr, -// regardless of type. -// - 1 If the argument should sort first. +// - -1 If the receiver should sort first because its port is lower than arg +// - 0 if the SockAddr arg's port number is equal to the receiving IPv6Addr, +// regardless of type. +// - 1 If the argument should sort first. func (ipv6 IPv6Addr) CmpPort(sa SockAddr) int { var saPort IPPort switch v := sa.(type) { @@ -220,10 +220,10 @@ func (ipv6 IPv6Addr) CmpPort(sa SockAddr) int { // CmpRFC follows the Cmp() standard protocol and returns: // -// - -1 If the receiver should sort first because it belongs to the RFC and its -// arg does not -// - 0 if the receiver and arg both belong to the same RFC or neither do. -// - 1 If the arg belongs to the RFC but receiver does not. +// - -1 If the receiver should sort first because it belongs to the RFC and its +// arg does not +// - 0 if the receiver and arg both belong to the same RFC or neither do. +// - 1 If the arg belongs to the RFC but receiver does not. func (ipv6 IPv6Addr) CmpRFC(rfcNum uint, sa SockAddr) int { recvInRFC := IsRFC(rfcNum, ipv6) ipv6b, ok := sa.(IPv6Addr) diff --git a/third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/hcl/printer/nodes.go b/third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/hcl/printer/nodes.go index 7c038d12a..f207bf92d 100644 --- a/third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/hcl/printer/nodes.go +++ b/third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/hcl/printer/nodes.go @@ -721,10 +721,9 @@ func (p *printer) heredocIndent(buf []byte) []byte { // // A single line object: // -// * has no lead comments (hence multi-line) -// * has no assignment -// * has no values in the stanza (within {}) -// +// - has no lead comments (hence multi-line) +// - has no assignment +// - has no values in the stanza (within {}) func (p *printer) isSingleLineObject(val *ast.ObjectItem) bool { // If there is a lead comment, can't be one line if val.LeadComment != nil {