Repository: sigstore/policy-controller Branch: main Commit: cc75baab1d34 Files: 813 Total size: 4.8 MB Directory structure: gitextract_s9p6qnqm/ ├── .gitattributes ├── .github/ │ ├── dependabot.yml │ └── workflows/ │ ├── build.yaml │ ├── codeql-analysis.yml │ ├── depsreview.yml │ ├── donotsubmit.yaml │ ├── kind-cluster-image-policy-no-tuf.yaml │ ├── kind-cluster-image-policy-trustroot.yaml │ ├── kind-cluster-image-policy-tsa.yaml │ ├── kind-cluster-image-policy.yaml │ ├── kind-e2e-cosigned.yaml │ ├── kind-e2e-trustroot-crd.yaml │ ├── lint.yaml │ ├── milestone.yaml │ ├── policy-tester-examples.yml │ ├── release-snapshot.yaml │ ├── release.yaml │ ├── scorecard_action.yml │ ├── style.yaml │ ├── tests.yaml │ ├── verify-codegen.yaml │ ├── verify-docs.yaml │ └── whitespace.yaml ├── .gitignore ├── .golangci.yml ├── .goreleaser.yaml ├── .ko.yaml ├── CHANGELOG.md ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── COPYRIGHT.txt ├── LICENSE ├── Makefile ├── README.md ├── cmd/ │ ├── api-docs/ │ │ └── main.go │ ├── local-dev/ │ │ ├── clean.go │ │ ├── main.go │ │ ├── root.go │ │ └── setup.go │ ├── sample/ │ │ └── main.go │ ├── schema/ │ │ └── main.go │ ├── tester/ │ │ ├── main.go │ │ └── trustroot.go │ └── webhook/ │ ├── depcheck_test.go │ └── main.go ├── config/ │ ├── 100-namespace.yaml │ ├── 200-clusterrole.yaml │ ├── 200-role.yaml │ ├── 200-serviceaccount.yaml │ ├── 201-clusterrolebinding.yaml │ ├── 201-rolebinding.yaml │ ├── 300-clusterimagepolicy.yaml │ ├── 300-trustroot.yaml │ ├── 400-webhook-service.yaml │ ├── 500-webhook-configuration.yaml │ ├── 501-policy-webhook-configurations.yaml │ ├── config-image-policies.yaml │ ├── config-leader-election.yaml │ ├── config-logging.yaml │ ├── config-observability.yaml │ ├── config-policy-controller.yaml │ ├── config-sigstore-keys.yaml │ ├── dummy.go │ ├── kustomization.yaml │ └── webhook.yaml ├── docs/ │ └── api-types/ │ ├── index-v1alpha1.md │ └── index.md ├── examples/ │ ├── README.md │ ├── keys/ │ │ ├── cosign.key │ │ └── cosign.pub │ ├── policies/ │ │ ├── allow-only-pods.yaml │ │ ├── custom-key-attestation-sbom-spdxjson.yaml │ │ ├── keyless-attestation-sbom-spdxjson.yaml │ │ ├── release-signed-by-github-actions.yaml │ │ ├── signed-by-aws-kms-key.yaml │ │ ├── signed-by-gcp-kms-key.yaml │ │ └── signed-by-github-actions.yaml │ └── sboms/ │ └── example.spdx.json ├── go.mod ├── go.sum ├── hack/ │ ├── boilerplate/ │ │ └── boilerplate.go.txt │ ├── gentestdata/ │ │ └── gentestdata.go │ ├── github-oidc-setup.sh │ ├── tools.go │ ├── update-codegen.sh │ └── update-deps.sh ├── images/ │ └── dot/ │ └── signatures.dot ├── pkg/ │ ├── apis/ │ │ ├── config/ │ │ │ ├── doc.go │ │ │ ├── image_policies.go │ │ │ ├── image_policies_test.go │ │ │ ├── sigstore_keys.go │ │ │ ├── sigstore_keys_test.go │ │ │ ├── store.go │ │ │ ├── store_test.go │ │ │ └── testdata/ │ │ │ ├── config-image-policies.yaml │ │ │ ├── config-invalid-image-policy.yaml │ │ │ └── config-sigstore-keys.yaml │ │ ├── duck/ │ │ │ └── v1beta1/ │ │ │ ├── doc.go │ │ │ ├── podscalable_defaults.go │ │ │ ├── podscalable_defaults_test.go │ │ │ ├── podscalable_implements_test.go │ │ │ ├── podscalable_types.go │ │ │ ├── podscalable_types_test.go │ │ │ ├── podscalable_validation.go │ │ │ ├── podscalable_validation_test.go │ │ │ ├── register.go │ │ │ └── zz_generated.deepcopy.go │ │ ├── glob/ │ │ │ ├── glob.go │ │ │ └── glob_test.go │ │ ├── policy/ │ │ │ ├── common/ │ │ │ │ ├── validation.go │ │ │ │ └── validation_test.go │ │ │ ├── register.go │ │ │ ├── v1alpha1/ │ │ │ │ ├── clusterimagepolicy_conversion.go │ │ │ │ ├── clusterimagepolicy_conversion_test.go │ │ │ │ ├── clusterimagepolicy_defaults.go │ │ │ │ ├── clusterimagepolicy_defaults_test.go │ │ │ │ ├── clusterimagepolicy_lifecycle.go │ │ │ │ ├── clusterimagepolicy_lifecycle_test.go │ │ │ │ ├── clusterimagepolicy_types.go │ │ │ │ ├── clusterimagepolicy_validation.go │ │ │ │ ├── clusterimagepolicy_validation_test.go │ │ │ │ ├── doc.go │ │ │ │ ├── register.go │ │ │ │ ├── trustroot_defaults.go │ │ │ │ ├── trustroot_defaults_test.go │ │ │ │ ├── trustroot_lifecycle.go │ │ │ │ ├── trustroot_types.go │ │ │ │ ├── trustroot_validation.go │ │ │ │ ├── trustroot_validation_test.go │ │ │ │ └── zz_generated.deepcopy.go │ │ │ └── v1beta1/ │ │ │ ├── clusterimagepolicy_conversion.go │ │ │ ├── clusterimagepolicy_conversion_test.go │ │ │ ├── clusterimagepolicy_defaults.go │ │ │ ├── clusterimagepolicy_defaults_test.go │ │ │ ├── clusterimagepolicy_lifecycle.go │ │ │ ├── clusterimagepolicy_types.go │ │ │ ├── clusterimagepolicy_validation.go │ │ │ ├── clusterimagepolicy_validation_test.go │ │ │ ├── doc.go │ │ │ ├── register.go │ │ │ └── zz_generated.deepcopy.go │ │ └── signaturealgo/ │ │ ├── signature_digest.go │ │ └── signature_digest_test.go │ ├── client/ │ │ ├── clientset/ │ │ │ └── versioned/ │ │ │ ├── clientset.go │ │ │ ├── doc.go │ │ │ ├── fake/ │ │ │ │ ├── clientset_generated.go │ │ │ │ ├── doc.go │ │ │ │ └── register.go │ │ │ ├── scheme/ │ │ │ │ ├── doc.go │ │ │ │ └── register.go │ │ │ └── typed/ │ │ │ ├── duck/ │ │ │ │ └── v1beta1/ │ │ │ │ ├── doc.go │ │ │ │ ├── duck_client.go │ │ │ │ ├── fake/ │ │ │ │ │ ├── doc.go │ │ │ │ │ └── fake_duck_client.go │ │ │ │ └── generated_expansion.go │ │ │ └── policy/ │ │ │ ├── v1alpha1/ │ │ │ │ ├── clusterimagepolicy.go │ │ │ │ ├── doc.go │ │ │ │ ├── fake/ │ │ │ │ │ ├── doc.go │ │ │ │ │ ├── fake_clusterimagepolicy.go │ │ │ │ │ ├── fake_policy_client.go │ │ │ │ │ └── fake_trustroot.go │ │ │ │ ├── generated_expansion.go │ │ │ │ ├── policy_client.go │ │ │ │ └── trustroot.go │ │ │ └── v1beta1/ │ │ │ ├── clusterimagepolicy.go │ │ │ ├── doc.go │ │ │ ├── fake/ │ │ │ │ ├── doc.go │ │ │ │ ├── fake_clusterimagepolicy.go │ │ │ │ └── fake_policy_client.go │ │ │ ├── generated_expansion.go │ │ │ └── policy_client.go │ │ ├── informers/ │ │ │ └── externalversions/ │ │ │ ├── factory.go │ │ │ ├── generic.go │ │ │ ├── internalinterfaces/ │ │ │ │ └── factory_interfaces.go │ │ │ └── policy/ │ │ │ ├── interface.go │ │ │ ├── v1alpha1/ │ │ │ │ ├── clusterimagepolicy.go │ │ │ │ ├── interface.go │ │ │ │ └── trustroot.go │ │ │ └── v1beta1/ │ │ │ ├── clusterimagepolicy.go │ │ │ └── interface.go │ │ ├── injection/ │ │ │ ├── client/ │ │ │ │ ├── client.go │ │ │ │ └── fake/ │ │ │ │ └── fake.go │ │ │ ├── ducks/ │ │ │ │ └── duck/ │ │ │ │ └── v1beta1/ │ │ │ │ └── podscalable/ │ │ │ │ ├── fake/ │ │ │ │ │ └── fake.go │ │ │ │ └── podscalable.go │ │ │ ├── informers/ │ │ │ │ ├── factory/ │ │ │ │ │ ├── factory.go │ │ │ │ │ ├── fake/ │ │ │ │ │ │ └── fake.go │ │ │ │ │ └── filtered/ │ │ │ │ │ ├── fake/ │ │ │ │ │ │ └── fake_filtered_factory.go │ │ │ │ │ └── filtered_factory.go │ │ │ │ └── policy/ │ │ │ │ ├── v1alpha1/ │ │ │ │ │ ├── clusterimagepolicy/ │ │ │ │ │ │ ├── clusterimagepolicy.go │ │ │ │ │ │ ├── fake/ │ │ │ │ │ │ │ └── fake.go │ │ │ │ │ │ └── filtered/ │ │ │ │ │ │ ├── clusterimagepolicy.go │ │ │ │ │ │ └── fake/ │ │ │ │ │ │ └── fake.go │ │ │ │ │ └── trustroot/ │ │ │ │ │ ├── fake/ │ │ │ │ │ │ └── fake.go │ │ │ │ │ ├── filtered/ │ │ │ │ │ │ ├── fake/ │ │ │ │ │ │ │ └── fake.go │ │ │ │ │ │ └── trustroot.go │ │ │ │ │ └── trustroot.go │ │ │ │ └── v1beta1/ │ │ │ │ └── clusterimagepolicy/ │ │ │ │ ├── clusterimagepolicy.go │ │ │ │ ├── fake/ │ │ │ │ │ └── fake.go │ │ │ │ └── filtered/ │ │ │ │ ├── clusterimagepolicy.go │ │ │ │ └── fake/ │ │ │ │ └── fake.go │ │ │ └── reconciler/ │ │ │ └── policy/ │ │ │ ├── v1alpha1/ │ │ │ │ ├── clusterimagepolicy/ │ │ │ │ │ ├── controller.go │ │ │ │ │ ├── reconciler.go │ │ │ │ │ └── state.go │ │ │ │ └── trustroot/ │ │ │ │ ├── controller.go │ │ │ │ ├── reconciler.go │ │ │ │ └── state.go │ │ │ └── v1beta1/ │ │ │ └── clusterimagepolicy/ │ │ │ ├── controller.go │ │ │ ├── reconciler.go │ │ │ └── state.go │ │ └── listers/ │ │ └── policy/ │ │ ├── v1alpha1/ │ │ │ ├── clusterimagepolicy.go │ │ │ ├── expansion_generated.go │ │ │ └── trustroot.go │ │ └── v1beta1/ │ │ ├── clusterimagepolicy.go │ │ └── expansion_generated.go │ ├── config/ │ │ ├── store.go │ │ ├── store_test.go │ │ └── testdata/ │ │ ├── allow-all.yaml │ │ ├── allow-empty-authorities.yaml │ │ ├── deny-all-default.yaml │ │ ├── deny-all-explicit.yaml │ │ ├── enable-oci11-invalid.yaml │ │ ├── enable-oci11.yaml │ │ └── warn-all.yaml │ ├── policy/ │ │ ├── README.md │ │ ├── parse.go │ │ ├── parse_test.go │ │ ├── policy.go │ │ ├── policy_test.go │ │ ├── validate.go │ │ ├── validate_test.go │ │ ├── verifier.go │ │ └── verifier_test.go │ ├── reconciler/ │ │ ├── clusterimagepolicy/ │ │ │ ├── clusterimagepolicy.go │ │ │ ├── clusterimagepolicy_test.go │ │ │ ├── controller.go │ │ │ ├── controller_test.go │ │ │ └── resources/ │ │ │ └── configmap.go │ │ ├── testing/ │ │ │ └── v1alpha1/ │ │ │ ├── clusterimagepolicy.go │ │ │ ├── factory.go │ │ │ ├── listers.go │ │ │ └── trustroot.go │ │ └── trustroot/ │ │ ├── controller.go │ │ ├── controller_test.go │ │ ├── resources/ │ │ │ └── configmap.go │ │ ├── testdata/ │ │ │ ├── ctfeLogID.txt │ │ │ ├── ctfePublicKey.pem │ │ │ ├── fulcioCert.pem │ │ │ ├── fulcioCertChain.pem │ │ │ ├── marshalledEntry.json │ │ │ ├── marshalledEntryFromMirrorFS.json │ │ │ ├── rekorLogID.txt │ │ │ ├── rekorPublicKey.pem │ │ │ ├── root.json │ │ │ ├── rootWithCustomTrustedRootJSON.json │ │ │ ├── rootWithTrustedRootJSON.json │ │ │ ├── testdata.go │ │ │ └── tsaCertChain.pem │ │ ├── trustroot.go │ │ └── trustroot_test.go │ ├── tuf/ │ │ ├── context.go │ │ ├── context_test.go │ │ ├── repo.go │ │ └── repo_test.go │ └── webhook/ │ ├── cache.go │ ├── clusterimagepolicy/ │ │ └── clusterimagepolicy_types.go │ ├── nocache.go │ ├── registryauth/ │ │ ├── azure/ │ │ │ └── acrhelper.go │ │ └── registryauth.go │ ├── testdata/ │ │ └── cert.pem │ ├── validation.go │ ├── validator.go │ ├── validator_result.go │ └── validator_test.go ├── release/ │ ├── README.md │ ├── ko-sign-release-images.sh │ ├── ldflags.sh │ └── release.mk ├── test/ │ ├── cert_utils.go │ ├── ci.mk │ ├── cmd/ │ │ └── getoidctoken/ │ │ └── main.go │ ├── config/ │ │ └── gettoken/ │ │ └── gettoken.yaml │ ├── e2e_test_cluster_image_policy.sh │ ├── e2e_test_cluster_image_policy_from_configmap_with_fetch_config_file.sh │ ├── e2e_test_cluster_image_policy_from_url.sh │ ├── e2e_test_cluster_image_policy_no_tuf.sh │ ├── e2e_test_cluster_image_policy_with_attestations.sh │ ├── e2e_test_cluster_image_policy_with_attestations_rego.sh │ ├── e2e_test_cluster_image_policy_with_fetch_config_file.sh │ ├── e2e_test_cluster_image_policy_with_include_objectmeta.sh │ ├── e2e_test_cluster_image_policy_with_include_spec.sh │ ├── e2e_test_cluster_image_policy_with_include_typemeta.sh │ ├── e2e_test_cluster_image_policy_with_oci11_attestations.sh │ ├── e2e_test_cluster_image_policy_with_source.sh │ ├── e2e_test_cluster_image_policy_with_trustroot_bring_own_keys.sh │ ├── e2e_test_cluster_image_policy_with_trustroot_remote.sh │ ├── e2e_test_cluster_image_policy_with_trustroot_repository.sh │ ├── e2e_test_cluster_image_policy_with_tsa.sh │ ├── e2e_test_cluster_image_policy_with_warn.sh │ ├── e2e_test_cluster_with_scalable.sh │ ├── e2e_test_policy_controller.sh │ ├── e2e_test_policy_crd.sh │ ├── e2e_test_trustroot_crd.sh │ ├── kustomize/ │ │ └── kustomization.yaml │ ├── kustomize-no-tuf/ │ │ └── kustomization.yaml │ └── testdata/ │ ├── attestations/ │ │ └── vuln-predicate.json │ ├── bom-go-mod.spdx │ ├── fancy_from.Dockerfile │ ├── policies/ │ │ ├── cue-fails.cue │ │ ├── cue-policy-config.cue │ │ ├── cue-vuln-fails.cue │ │ ├── cue-vuln-works.cue │ │ └── cue-works.cue │ ├── resources/ │ │ ├── job.yaml │ │ └── pod.yaml │ ├── signed_manifest.yaml │ ├── single_stage.Dockerfile │ ├── test.wasm │ ├── test_blob_cert.pem │ ├── test_blob_private_key │ ├── test_blob_public_key │ ├── trustroot/ │ │ ├── e2e/ │ │ │ ├── bring-your-own-keys.yaml │ │ │ ├── with-remote.yaml │ │ │ ├── with-repository.yaml │ │ │ └── with-tsa.yaml │ │ ├── golden/ │ │ │ ├── ctfe.pem │ │ │ ├── fulcio.crt.pem │ │ │ ├── rekor.pem │ │ │ └── tsa.crt.pem │ │ └── valid/ │ │ └── valid-sigstore-keys.yaml │ ├── unsigned_build_stage.Dockerfile │ ├── unsigned_manifest.yaml │ ├── with_arg.Dockerfile │ └── with_lowercase.Dockerfile └── third_party/ └── VENDOR-LICENSE/ ├── cloud.google.com/ │ └── go/ │ ├── auth/ │ │ ├── LICENSE │ │ └── oauth2adapt/ │ │ └── LICENSE │ ├── compute/ │ │ └── metadata/ │ │ └── LICENSE │ ├── iam/ │ │ └── LICENSE │ ├── kms/ │ │ └── LICENSE │ └── longrunning/ │ └── LICENSE ├── contrib.go.opencensus.io/ │ └── exporter/ │ ├── ocagent/ │ │ └── LICENSE │ └── prometheus/ │ └── LICENSE ├── cuelang.org/ │ └── go/ │ └── LICENSE ├── github.com/ │ ├── AliyunContainerService/ │ │ └── ack-ram-tool/ │ │ └── pkg/ │ │ └── credentials/ │ │ └── provider/ │ │ └── LICENSE │ ├── Azure/ │ │ ├── azure-sdk-for-go/ │ │ │ ├── LICENSE.txt │ │ │ ├── NOTICE.txt │ │ │ └── sdk/ │ │ │ ├── azcore/ │ │ │ │ └── LICENSE.txt │ │ │ ├── azidentity/ │ │ │ │ └── LICENSE.txt │ │ │ ├── internal/ │ │ │ │ └── LICENSE.txt │ │ │ └── security/ │ │ │ └── keyvault/ │ │ │ ├── azkeys/ │ │ │ │ └── LICENSE.txt │ │ │ └── internal/ │ │ │ └── LICENSE.txt │ │ └── go-autorest/ │ │ ├── autorest/ │ │ │ ├── LICENSE │ │ │ ├── adal/ │ │ │ │ └── LICENSE │ │ │ ├── azure/ │ │ │ │ ├── auth/ │ │ │ │ │ └── LICENSE │ │ │ │ └── cli/ │ │ │ │ └── LICENSE │ │ │ └── date/ │ │ │ └── LICENSE │ │ ├── logger/ │ │ │ └── LICENSE │ │ └── tracing/ │ │ └── LICENSE │ ├── AzureAD/ │ │ └── microsoft-authentication-library-for-go/ │ │ └── apps/ │ │ └── LICENSE │ ├── LICENSE │ ├── agnivade/ │ │ └── levenshtein/ │ │ └── License.txt │ ├── alibabacloud-go/ │ │ ├── alibabacloud-gateway-spi/ │ │ │ └── client/ │ │ │ └── LICENSE │ │ ├── cr-20181201/ │ │ │ └── client/ │ │ │ └── LICENSE │ │ ├── darabonba-openapi/ │ │ │ └── client/ │ │ │ └── LICENSE │ │ ├── debug/ │ │ │ └── debug/ │ │ │ └── LICENSE │ │ ├── endpoint-util/ │ │ │ └── service/ │ │ │ └── LICENSE │ │ ├── openapi-util/ │ │ │ └── service/ │ │ │ └── LICENSE │ │ ├── tea/ │ │ │ └── LICENSE │ │ ├── tea-utils/ │ │ │ └── service/ │ │ │ └── LICENSE │ │ └── tea-xml/ │ │ └── service/ │ │ └── LICENSE │ ├── aliyun/ │ │ └── credentials-go/ │ │ └── credentials/ │ │ └── LICENSE │ ├── asaskevich/ │ │ └── govalidator/ │ │ └── LICENSE │ ├── aws/ │ │ ├── aws-sdk-go-v2/ │ │ │ ├── LICENSE.txt │ │ │ ├── NOTICE.txt │ │ │ ├── config/ │ │ │ │ └── LICENSE.txt │ │ │ ├── credentials/ │ │ │ │ └── LICENSE.txt │ │ │ ├── feature/ │ │ │ │ └── ec2/ │ │ │ │ └── imds/ │ │ │ │ └── LICENSE.txt │ │ │ ├── internal/ │ │ │ │ ├── configsources/ │ │ │ │ │ └── LICENSE.txt │ │ │ │ ├── endpoints/ │ │ │ │ │ └── v2/ │ │ │ │ │ └── LICENSE.txt │ │ │ │ ├── ini/ │ │ │ │ │ └── LICENSE.txt │ │ │ │ └── sync/ │ │ │ │ └── singleflight/ │ │ │ │ └── LICENSE │ │ │ └── service/ │ │ │ ├── ecr/ │ │ │ │ └── LICENSE.txt │ │ │ ├── ecrpublic/ │ │ │ │ └── LICENSE.txt │ │ │ ├── internal/ │ │ │ │ ├── accept-encoding/ │ │ │ │ │ └── LICENSE.txt │ │ │ │ └── presigned-url/ │ │ │ │ └── LICENSE.txt │ │ │ ├── kms/ │ │ │ │ └── LICENSE.txt │ │ │ ├── signin/ │ │ │ │ └── LICENSE.txt │ │ │ ├── sso/ │ │ │ │ └── LICENSE.txt │ │ │ ├── ssooidc/ │ │ │ │ └── LICENSE.txt │ │ │ └── sts/ │ │ │ └── LICENSE.txt │ │ └── smithy-go/ │ │ ├── LICENSE │ │ ├── NOTICE │ │ └── internal/ │ │ └── sync/ │ │ └── singleflight/ │ │ └── LICENSE │ ├── awslabs/ │ │ └── amazon-ecr-credential-helper/ │ │ └── ecr-login/ │ │ └── LICENSE │ ├── beorn7/ │ │ └── perks/ │ │ └── quantile/ │ │ └── LICENSE │ ├── blang/ │ │ └── semver/ │ │ ├── LICENSE │ │ └── v4/ │ │ └── LICENSE │ ├── blendle/ │ │ └── zapdriver/ │ │ └── LICENSE │ ├── cenkalti/ │ │ └── backoff/ │ │ ├── v4/ │ │ │ └── LICENSE │ │ └── v5/ │ │ └── LICENSE │ ├── census-instrumentation/ │ │ └── opencensus-proto/ │ │ └── gen-go/ │ │ └── LICENSE │ ├── cespare/ │ │ └── xxhash/ │ │ └── v2/ │ │ └── LICENSE.txt │ ├── chrismellard/ │ │ └── docker-credential-acr-env/ │ │ └── pkg/ │ │ └── LICENSE │ ├── clbanning/ │ │ └── mxj/ │ │ └── v2/ │ │ └── LICENSE │ ├── cockroachdb/ │ │ └── apd/ │ │ └── v3/ │ │ └── LICENSE │ ├── common-nighthawk/ │ │ └── go-figure/ │ │ └── LICENSE │ ├── containerd/ │ │ ├── errdefs/ │ │ │ ├── LICENSE │ │ │ └── pkg/ │ │ │ └── LICENSE │ │ └── stargz-snapshotter/ │ │ └── estargz/ │ │ └── LICENSE │ ├── coreos/ │ │ └── go-oidc/ │ │ └── v3/ │ │ └── oidc/ │ │ ├── LICENSE │ │ └── NOTICE │ ├── cyberphone/ │ │ └── json-canonicalization/ │ │ └── go/ │ │ └── src/ │ │ └── webpki.org/ │ │ └── jsoncanonicalizer/ │ │ └── LICENSE │ ├── davecgh/ │ │ └── go-spew/ │ │ └── spew/ │ │ └── LICENSE │ ├── digitorus/ │ │ ├── pkcs7/ │ │ │ └── LICENSE │ │ └── timestamp/ │ │ └── LICENSE │ ├── dimchansky/ │ │ └── utfbom/ │ │ └── LICENSE │ ├── distribution/ │ │ └── reference/ │ │ └── LICENSE │ ├── docker/ │ │ ├── cli/ │ │ │ └── cli/ │ │ │ └── config/ │ │ │ ├── LICENSE │ │ │ └── NOTICE │ │ ├── distribution/ │ │ │ └── registry/ │ │ │ └── client/ │ │ │ └── auth/ │ │ │ └── challenge/ │ │ │ └── LICENSE │ │ ├── docker/ │ │ │ ├── LICENSE │ │ │ └── NOTICE │ │ ├── docker-credential-helpers/ │ │ │ └── LICENSE │ │ ├── go-connections/ │ │ │ └── LICENSE │ │ └── go-units/ │ │ └── LICENSE │ ├── dustin/ │ │ └── go-humanize/ │ │ └── LICENSE │ ├── emicklei/ │ │ ├── go-restful/ │ │ │ └── v3/ │ │ │ └── LICENSE │ │ └── proto/ │ │ └── LICENSE │ ├── evanphx/ │ │ └── json-patch/ │ │ └── v5/ │ │ └── LICENSE │ ├── felixge/ │ │ └── httpsnoop/ │ │ └── LICENSE.txt │ ├── fsnotify/ │ │ └── fsnotify/ │ │ └── LICENSE │ ├── fxamacker/ │ │ └── cbor/ │ │ └── v2/ │ │ └── LICENSE │ ├── go-chi/ │ │ └── chi/ │ │ └── v5/ │ │ └── LICENSE │ ├── go-ini/ │ │ └── ini/ │ │ └── LICENSE │ ├── go-jose/ │ │ └── go-jose/ │ │ └── v4/ │ │ ├── LICENSE │ │ └── json/ │ │ └── LICENSE │ ├── go-kit/ │ │ └── log/ │ │ └── LICENSE │ ├── go-logfmt/ │ │ └── logfmt/ │ │ └── LICENSE │ ├── go-logr/ │ │ ├── logr/ │ │ │ └── LICENSE │ │ └── stdr/ │ │ └── LICENSE │ ├── go-openapi/ │ │ ├── analysis/ │ │ │ └── LICENSE │ │ ├── errors/ │ │ │ └── LICENSE │ │ ├── jsonpointer/ │ │ │ ├── LICENSE │ │ │ └── NOTICE │ │ ├── jsonreference/ │ │ │ ├── LICENSE │ │ │ └── NOTICE │ │ ├── loads/ │ │ │ └── LICENSE │ │ ├── runtime/ │ │ │ ├── LICENSE │ │ │ └── middleware/ │ │ │ └── denco/ │ │ │ └── LICENSE │ │ ├── spec/ │ │ │ └── LICENSE │ │ ├── strfmt/ │ │ │ └── LICENSE │ │ ├── swag/ │ │ │ ├── LICENSE │ │ │ ├── cmdutils/ │ │ │ │ └── LICENSE │ │ │ ├── conv/ │ │ │ │ └── LICENSE │ │ │ ├── fileutils/ │ │ │ │ └── LICENSE │ │ │ ├── jsonname/ │ │ │ │ └── LICENSE │ │ │ ├── jsonutils/ │ │ │ │ └── LICENSE │ │ │ ├── loading/ │ │ │ │ └── LICENSE │ │ │ ├── mangling/ │ │ │ │ └── LICENSE │ │ │ ├── netutils/ │ │ │ │ └── LICENSE │ │ │ ├── stringutils/ │ │ │ │ └── LICENSE │ │ │ ├── typeutils/ │ │ │ │ └── LICENSE │ │ │ └── yamlutils/ │ │ │ └── LICENSE │ │ └── validate/ │ │ └── LICENSE │ ├── go-viper/ │ │ └── mapstructure/ │ │ └── v2/ │ │ └── LICENSE │ ├── gobuffalo/ │ │ └── flect/ │ │ └── LICENSE │ ├── gobwas/ │ │ └── glob/ │ │ └── LICENSE │ ├── gogo/ │ │ └── protobuf/ │ │ └── LICENSE │ ├── golang/ │ │ ├── groupcache/ │ │ │ └── lru/ │ │ │ └── LICENSE │ │ ├── protobuf/ │ │ │ └── ptypes/ │ │ │ └── timestamp/ │ │ │ └── LICENSE │ │ └── snappy/ │ │ └── LICENSE │ ├── golang-jwt/ │ │ └── jwt/ │ │ ├── v4/ │ │ │ └── LICENSE │ │ └── v5/ │ │ └── LICENSE │ ├── google/ │ │ ├── certificate-transparency-go/ │ │ │ └── LICENSE │ │ ├── gnostic-models/ │ │ │ └── LICENSE │ │ ├── go-cmp/ │ │ │ └── cmp/ │ │ │ └── LICENSE │ │ ├── go-containerregistry/ │ │ │ ├── LICENSE │ │ │ └── pkg/ │ │ │ └── authn/ │ │ │ ├── k8schain/ │ │ │ │ └── LICENSE │ │ │ └── kubernetes/ │ │ │ └── LICENSE │ │ ├── go-github/ │ │ │ └── v73/ │ │ │ └── github/ │ │ │ └── LICENSE │ │ ├── go-querystring/ │ │ │ └── query/ │ │ │ └── LICENSE │ │ ├── s2a-go/ │ │ │ └── LICENSE.md │ │ └── uuid/ │ │ └── LICENSE │ ├── googleapis/ │ │ ├── enterprise-certificate-proxy/ │ │ │ └── client/ │ │ │ └── LICENSE │ │ └── gax-go/ │ │ └── v2/ │ │ └── LICENSE │ ├── grpc-ecosystem/ │ │ └── grpc-gateway/ │ │ └── v2/ │ │ └── LICENSE │ ├── hashicorp/ │ │ ├── errwrap/ │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ └── errwrap.go │ │ ├── go-cleanhttp/ │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── cleanhttp.go │ │ │ ├── doc.go │ │ │ └── handlers.go │ │ ├── go-multierror/ │ │ │ ├── LICENSE │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── append.go │ │ │ ├── flatten.go │ │ │ ├── format.go │ │ │ ├── group.go │ │ │ ├── multierror.go │ │ │ ├── prefix.go │ │ │ └── sort.go │ │ ├── go-retryablehttp/ │ │ │ ├── .gitignore │ │ │ ├── .go-version │ │ │ ├── .golangci.yml │ │ │ ├── CHANGELOG.md │ │ │ ├── CODEOWNERS │ │ │ ├── LICENSE │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── cert_error_go119.go │ │ │ ├── cert_error_go120.go │ │ │ ├── client.go │ │ │ └── roundtripper.go │ │ ├── go-rootcerts/ │ │ │ ├── .travis.yml │ │ │ ├── LICENSE │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── doc.go │ │ │ ├── rootcerts.go │ │ │ ├── rootcerts_base.go │ │ │ └── rootcerts_darwin.go │ │ ├── go-secure-stdlib/ │ │ │ ├── parseutil/ │ │ │ │ ├── LICENSE │ │ │ │ ├── normalize.go │ │ │ │ ├── parsepath.go │ │ │ │ └── parseutil.go │ │ │ └── strutil/ │ │ │ ├── LICENSE │ │ │ └── strutil.go │ │ ├── go-sockaddr/ │ │ │ ├── .gitignore │ │ │ ├── GNUmakefile │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── doc.go │ │ │ ├── ifaddr.go │ │ │ ├── ifaddrs.go │ │ │ ├── ifattr.go │ │ │ ├── ipaddr.go │ │ │ ├── ipaddrs.go │ │ │ ├── ipv4addr.go │ │ │ ├── ipv6addr.go │ │ │ ├── rfc.go │ │ │ ├── route_info.go │ │ │ ├── route_info_aix.go │ │ │ ├── route_info_android.go │ │ │ ├── route_info_bsd.go │ │ │ ├── route_info_default.go │ │ │ ├── route_info_linux.go │ │ │ ├── route_info_solaris.go │ │ │ ├── route_info_test_windows.go │ │ │ ├── route_info_windows.go │ │ │ ├── sockaddr.go │ │ │ ├── sockaddrs.go │ │ │ └── unixsock.go │ │ ├── golang-lru/ │ │ │ ├── .gitignore │ │ │ ├── .golangci.yml │ │ │ ├── 2q.go │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── arc.go │ │ │ ├── doc.go │ │ │ ├── lru.go │ │ │ ├── simplelru/ │ │ │ │ ├── lru.go │ │ │ │ └── lru_interface.go │ │ │ └── testing.go │ │ ├── hcl/ │ │ │ ├── .gitignore │ │ │ ├── .travis.yml │ │ │ ├── LICENSE │ │ │ ├── Makefile │ │ │ ├── README.md │ │ │ ├── appveyor.yml │ │ │ ├── decoder.go │ │ │ ├── hcl/ │ │ │ │ ├── ast/ │ │ │ │ │ ├── ast.go │ │ │ │ │ └── walk.go │ │ │ │ ├── parser/ │ │ │ │ │ ├── error.go │ │ │ │ │ └── parser.go │ │ │ │ ├── scanner/ │ │ │ │ │ └── scanner.go │ │ │ │ ├── strconv/ │ │ │ │ │ └── quote.go │ │ │ │ └── token/ │ │ │ │ ├── position.go │ │ │ │ └── token.go │ │ │ ├── hcl.go │ │ │ ├── json/ │ │ │ │ ├── parser/ │ │ │ │ │ ├── flatten.go │ │ │ │ │ └── parser.go │ │ │ │ ├── scanner/ │ │ │ │ │ └── scanner.go │ │ │ │ └── token/ │ │ │ │ ├── position.go │ │ │ │ └── token.go │ │ │ ├── lex.go │ │ │ └── parse.go │ │ └── vault/ │ │ └── api/ │ │ ├── .copywrite.hcl │ │ ├── LICENSE │ │ ├── README.md │ │ ├── auth.go │ │ ├── auth_token.go │ │ ├── cliconfig/ │ │ │ ├── config.go │ │ │ ├── hcl_dup_attr_deprecation.go │ │ │ └── util.go │ │ ├── client.go │ │ ├── hcl_dup_attr_deprecation.go │ │ ├── help.go │ │ ├── kv.go │ │ ├── kv_v1.go │ │ ├── kv_v2.go │ │ ├── lifetime_watcher.go │ │ ├── logical.go │ │ ├── logical_requests.go │ │ ├── output_policy.go │ │ ├── output_string.go │ │ ├── plugin_helpers.go │ │ ├── plugin_runtime_types.go │ │ ├── plugin_types.go │ │ ├── pluginruntimetype_enumer.go │ │ ├── renewbehavior_enumer.go │ │ ├── replication_status.go │ │ ├── request.go │ │ ├── response.go │ │ ├── secret.go │ │ ├── ssh.go │ │ ├── ssh_agent.go │ │ ├── sudo_paths.go │ │ ├── sys.go │ │ ├── sys_audit.go │ │ ├── sys_auth.go │ │ ├── sys_capabilities.go │ │ ├── sys_config_cors.go │ │ ├── sys_generate_root.go │ │ ├── sys_hastatus.go │ │ ├── sys_health.go │ │ ├── sys_init.go │ │ ├── sys_leader.go │ │ ├── sys_leases.go │ │ ├── sys_mfa.go │ │ ├── sys_monitor.go │ │ ├── sys_mounts.go │ │ ├── sys_plugins.go │ │ ├── sys_plugins_runtimes.go │ │ ├── sys_policy.go │ │ ├── sys_raft.go │ │ ├── sys_rekey.go │ │ ├── sys_rotate.go │ │ ├── sys_seal.go │ │ ├── sys_stepdown.go │ │ ├── sys_ui_custom_message.go │ │ ├── sys_utilization_report.go │ │ └── tokenhelper/ │ │ ├── helper.go │ │ ├── helper_external.go │ │ ├── helper_internal.go │ │ └── testing.go │ ├── in-toto/ │ │ ├── attestation/ │ │ │ └── go/ │ │ │ └── v1/ │ │ │ └── LICENSE │ │ └── in-toto-golang/ │ │ └── in_toto/ │ │ └── LICENSE │ ├── jedisct1/ │ │ └── go-minisign/ │ │ └── LICENSE │ ├── jellydator/ │ │ └── ttlcache/ │ │ └── v3/ │ │ └── LICENSE │ ├── json-iterator/ │ │ └── go/ │ │ └── LICENSE │ ├── kelseyhightower/ │ │ └── envconfig/ │ │ └── LICENSE │ ├── klauspost/ │ │ └── compress/ │ │ ├── LICENSE │ │ ├── internal/ │ │ │ └── snapref/ │ │ │ └── LICENSE │ │ └── zstd/ │ │ └── internal/ │ │ └── xxhash/ │ │ └── LICENSE.txt │ ├── kylelemons/ │ │ └── godebug/ │ │ └── LICENSE │ ├── lestrrat-go/ │ │ ├── blackmagic/ │ │ │ └── LICENSE │ │ ├── dsig/ │ │ │ └── LICENSE │ │ ├── httpcc/ │ │ │ └── LICENSE │ │ ├── httprc/ │ │ │ └── v3/ │ │ │ └── LICENSE │ │ ├── jwx/ │ │ │ └── v3/ │ │ │ └── LICENSE │ │ └── option/ │ │ ├── LICENSE │ │ └── v2/ │ │ └── LICENSE │ ├── letsencrypt/ │ │ └── boulder/ │ │ ├── LICENSE.txt │ │ ├── core/ │ │ │ ├── challenges.go │ │ │ ├── interfaces.go │ │ │ ├── objects.go │ │ │ ├── proto/ │ │ │ │ ├── core.pb.go │ │ │ │ └── core.proto │ │ │ └── util.go │ │ ├── goodkey/ │ │ │ └── good_key.go │ │ ├── identifier/ │ │ │ └── identifier.go │ │ ├── probs/ │ │ │ └── probs.go │ │ └── revocation/ │ │ └── reasons.go │ ├── mitchellh/ │ │ ├── go-homedir/ │ │ │ └── LICENSE │ │ ├── go-wordwrap/ │ │ │ └── LICENSE.md │ │ └── mapstructure/ │ │ └── LICENSE │ ├── moby/ │ │ ├── docker-image-spec/ │ │ │ └── specs-go/ │ │ │ └── v1/ │ │ │ └── LICENSE │ │ └── term/ │ │ └── LICENSE │ ├── modern-go/ │ │ ├── concurrent/ │ │ │ └── LICENSE │ │ └── reflect2/ │ │ └── LICENSE │ ├── mozillazg/ │ │ └── docker-credential-acr-helper/ │ │ └── pkg/ │ │ └── LICENSE │ ├── munnerz/ │ │ └── goautoneg/ │ │ └── LICENSE │ ├── natefinch/ │ │ └── atomic/ │ │ └── LICENSE │ ├── nozzle/ │ │ └── throttler/ │ │ └── LICENSE │ ├── oklog/ │ │ └── ulid/ │ │ └── LICENSE │ ├── open-policy-agent/ │ │ └── opa/ │ │ ├── LICENSE │ │ └── internal/ │ │ ├── edittree/ │ │ │ └── bitvector/ │ │ │ └── license.txt │ │ ├── gojsonschema/ │ │ │ └── LICENSE-APACHE-2.0.txt │ │ └── semver/ │ │ └── LICENSE │ ├── opencontainers/ │ │ ├── go-digest/ │ │ │ └── LICENSE │ │ └── image-spec/ │ │ └── specs-go/ │ │ └── LICENSE │ ├── pelletier/ │ │ └── go-toml/ │ │ └── v2/ │ │ └── LICENSE │ ├── pkg/ │ │ ├── browser/ │ │ │ └── LICENSE │ │ └── errors/ │ │ └── LICENSE │ ├── pmezard/ │ │ └── go-difflib/ │ │ └── difflib/ │ │ └── LICENSE │ ├── prometheus/ │ │ ├── client_golang/ │ │ │ ├── internal/ │ │ │ │ └── github.com/ │ │ │ │ └── golang/ │ │ │ │ └── gddo/ │ │ │ │ └── httputil/ │ │ │ │ └── LICENSE │ │ │ └── prometheus/ │ │ │ ├── LICENSE │ │ │ └── NOTICE │ │ ├── client_model/ │ │ │ └── go/ │ │ │ ├── LICENSE │ │ │ └── NOTICE │ │ ├── common/ │ │ │ ├── LICENSE │ │ │ └── NOTICE │ │ ├── procfs/ │ │ │ ├── LICENSE │ │ │ └── NOTICE │ │ └── statsd_exporter/ │ │ └── pkg/ │ │ ├── LICENSE │ │ └── NOTICE │ ├── protocolbuffers/ │ │ └── txtpbfmt/ │ │ └── LICENSE │ ├── rcrowley/ │ │ └── go-metrics/ │ │ └── LICENSE │ ├── ryanuber/ │ │ └── go-glob/ │ │ └── LICENSE │ ├── sagikazarmark/ │ │ └── locafero/ │ │ └── LICENSE │ ├── sassoftware/ │ │ └── relic/ │ │ └── lib/ │ │ └── LICENSE │ ├── secure-systems-lab/ │ │ └── go-securesystemslib/ │ │ └── LICENSE │ ├── shibumi/ │ │ └── go-pathspec/ │ │ └── LICENSE │ ├── sigstore/ │ │ ├── cosign/ │ │ │ └── v3/ │ │ │ └── LICENSE │ │ ├── protobuf-specs/ │ │ │ └── gen/ │ │ │ └── pb-go/ │ │ │ └── LICENSE │ │ ├── rekor/ │ │ │ └── pkg/ │ │ │ └── LICENSE │ │ ├── rekor-tiles/ │ │ │ └── v2/ │ │ │ └── LICENSE │ │ ├── scaffolding/ │ │ │ └── pkg/ │ │ │ └── repo/ │ │ │ └── LICENSE │ │ ├── sigstore/ │ │ │ └── pkg/ │ │ │ ├── LICENSE │ │ │ └── signature/ │ │ │ └── kms/ │ │ │ ├── aws/ │ │ │ │ └── LICENSE │ │ │ ├── azure/ │ │ │ │ └── LICENSE │ │ │ ├── gcp/ │ │ │ │ └── LICENSE │ │ │ └── hashivault/ │ │ │ └── LICENSE │ │ ├── sigstore-go/ │ │ │ └── pkg/ │ │ │ └── LICENSE │ │ └── timestamp-authority/ │ │ └── v2/ │ │ └── pkg/ │ │ └── verification/ │ │ └── LICENSE │ ├── sirupsen/ │ │ └── logrus/ │ │ └── LICENSE │ ├── sourcegraph/ │ │ └── conc/ │ │ └── LICENSE │ ├── spf13/ │ │ ├── afero/ │ │ │ └── LICENSE.txt │ │ ├── cast/ │ │ │ └── LICENSE │ │ ├── cobra/ │ │ │ └── LICENSE.txt │ │ ├── pflag/ │ │ │ └── LICENSE │ │ └── viper/ │ │ └── LICENSE │ ├── subosito/ │ │ └── gotenv/ │ │ └── LICENSE │ ├── syndtr/ │ │ └── goleveldb/ │ │ └── leveldb/ │ │ └── LICENSE │ ├── tchap/ │ │ └── go-patricia/ │ │ └── v2/ │ │ └── patricia/ │ │ └── LICENSE │ ├── theupdateframework/ │ │ └── go-tuf/ │ │ ├── LICENSE │ │ └── v2/ │ │ └── metadata/ │ │ ├── LICENSE │ │ └── NOTICE │ ├── titanous/ │ │ └── rocacheck/ │ │ └── LICENSE │ ├── tjfoc/ │ │ └── gmsm/ │ │ └── sm3/ │ │ └── LICENSE │ ├── transparency-dev/ │ │ ├── formats/ │ │ │ └── log/ │ │ │ └── LICENSE │ │ └── merkle/ │ │ └── LICENSE │ ├── valyala/ │ │ └── fastjson/ │ │ └── LICENSE │ ├── vbatts/ │ │ └── tar-split/ │ │ └── archive/ │ │ └── tar/ │ │ └── LICENSE │ ├── vektah/ │ │ └── gqlparser/ │ │ └── v2/ │ │ └── LICENSE │ ├── x448/ │ │ └── float16/ │ │ └── LICENSE │ ├── xeipuuv/ │ │ ├── gojsonpointer/ │ │ │ └── LICENSE-APACHE-2.0.txt │ │ └── gojsonreference/ │ │ └── LICENSE-APACHE-2.0.txt │ └── yashtewari/ │ └── glob-intersection/ │ └── LICENSE ├── gitlab.com/ │ └── gitlab-org/ │ └── api/ │ └── client-go/ │ └── LICENSE ├── go.mongodb.org/ │ └── mongo-driver/ │ └── LICENSE ├── go.opencensus.io/ │ └── LICENSE ├── go.opentelemetry.io/ │ ├── auto/ │ │ └── sdk/ │ │ └── LICENSE │ ├── contrib/ │ │ └── instrumentation/ │ │ ├── google.golang.org/ │ │ │ └── grpc/ │ │ │ └── otelgrpc/ │ │ │ └── LICENSE │ │ └── net/ │ │ └── http/ │ │ └── otelhttp/ │ │ └── LICENSE │ └── otel/ │ ├── LICENSE │ ├── metric/ │ │ └── LICENSE │ ├── sdk/ │ │ └── LICENSE │ └── trace/ │ └── LICENSE ├── go.uber.org/ │ ├── atomic/ │ │ └── LICENSE.txt │ ├── automaxprocs/ │ │ └── LICENSE │ ├── multierr/ │ │ └── LICENSE.txt │ └── zap/ │ └── LICENSE ├── go.yaml.in/ │ └── yaml/ │ ├── v2/ │ │ ├── LICENSE │ │ └── NOTICE │ └── v3/ │ ├── LICENSE │ └── NOTICE ├── golang.org/ │ └── x/ │ ├── crypto/ │ │ └── LICENSE │ ├── mod/ │ │ └── LICENSE │ ├── net/ │ │ └── LICENSE │ ├── oauth2/ │ │ └── LICENSE │ ├── sync/ │ │ └── LICENSE │ ├── sys/ │ │ └── LICENSE │ ├── term/ │ │ └── LICENSE │ ├── text/ │ │ └── LICENSE │ └── time/ │ └── rate/ │ └── LICENSE ├── gomodules.xyz/ │ └── jsonpatch/ │ └── v2/ │ └── LICENSE ├── google.golang.org/ │ ├── api/ │ │ ├── LICENSE │ │ └── internal/ │ │ └── third_party/ │ │ └── uritemplates/ │ │ └── LICENSE │ ├── genproto/ │ │ └── googleapis/ │ │ ├── LICENSE │ │ ├── api/ │ │ │ └── LICENSE │ │ └── rpc/ │ │ └── LICENSE │ ├── grpc/ │ │ ├── LICENSE │ │ └── NOTICE.txt │ └── protobuf/ │ └── LICENSE ├── gopkg.in/ │ ├── evanphx/ │ │ └── json-patch.v4/ │ │ └── LICENSE │ ├── inf.v0/ │ │ └── LICENSE │ ├── ini.v1/ │ │ └── LICENSE │ ├── yaml.v2/ │ │ ├── LICENSE │ │ └── NOTICE │ └── yaml.v3/ │ ├── LICENSE │ └── NOTICE ├── k8s.io/ │ ├── api/ │ │ └── LICENSE │ ├── apiextensions-apiserver/ │ │ └── pkg/ │ │ └── LICENSE │ ├── apimachinery/ │ │ ├── pkg/ │ │ │ └── LICENSE │ │ └── third_party/ │ │ └── forked/ │ │ └── golang/ │ │ └── LICENSE │ ├── client-go/ │ │ └── LICENSE │ ├── klog/ │ │ └── v2/ │ │ └── LICENSE │ ├── kube-openapi/ │ │ └── pkg/ │ │ ├── LICENSE │ │ ├── internal/ │ │ │ └── third_party/ │ │ │ └── go-json-experiment/ │ │ │ └── json/ │ │ │ └── LICENSE │ │ └── validation/ │ │ └── spec/ │ │ └── LICENSE │ └── utils/ │ ├── LICENSE │ └── internal/ │ └── third_party/ │ └── forked/ │ └── golang/ │ └── LICENSE ├── knative.dev/ │ ├── hack/ │ │ └── schema/ │ │ └── LICENSE │ └── pkg/ │ └── LICENSE └── sigs.k8s.io/ ├── json/ │ └── LICENSE ├── randfill/ │ ├── LICENSE │ └── NOTICE ├── release-utils/ │ └── version/ │ └── LICENSE ├── structured-merge-diff/ │ └── v6/ │ └── LICENSE └── yaml/ └── LICENSE ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ # This file is documented at https://git-scm.com/docs/gitattributes. # Linguist-specific attributes are documented at # https://github.com/github/linguist. doc/cosign*.md linguist-generated=true ================================================ FILE: .github/dependabot.yml ================================================ # # Copyright 2021 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. version: 2 updates: - package-ecosystem: gomod directory: "/" schedule: interval: weekly open-pull-requests-limit: 10 groups: sigstore: patterns: - "github.com/sigstore/**" minor-patch: update-types: ["minor", "patch"] - package-ecosystem: "github-actions" directory: "/" schedule: interval: weekly open-pull-requests-limit: 10 groups: minor-patch: update-types: ["minor", "patch"] ================================================ FILE: .github/workflows/build.yaml ================================================ # # Copyright 2021 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: CI-Container-Build on: push: branches: - main - release-* permissions: {} jobs: build: name: build runs-on: ubuntu-latest permissions: id-token: write contents: read packages: write steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 # v3.9.2 - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: './go.mod' check-latest: true # will use the latest release available for ko - uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9 - uses: chainguard-dev/actions/goimports@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 - name: Set up Cloud SDK uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 with: workload_identity_provider: 'projects/498091336538/locations/global/workloadIdentityPools/githubactions/providers/sigstore-policy-controller' service_account: 'gha-policy-controller@projectsigstore.iam.gserviceaccount.com' - name: creds run: gcloud auth configure-docker --quiet - name: policy-controller run: COSIGN_YES="true" KO_PREFIX=ghcr.io/sigstore/policy-controller/policy-controller/ci make build-sign-containers ================================================ FILE: .github/workflows/codeql-analysis.yml ================================================ # # Copyright 2021 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: CodeQL on: push: branches: [ main ] schedule: - cron: '45 10 * * 1' env: CODEQL_EXTRACTOR_GO_BUILD_TRACING: true jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: security-events: write actions: read contents: read strategy: fail-fast: false matrix: language: [ 'go' ] steps: - name: Checkout repository uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Utilize Go Module Cache uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: | ~/go/pkg/mod ~/.cache/go-build key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - name: Set correct version of Golang to use during CodeQL run uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: './go.mod' check-latest: true # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5 with: languages: ${{ matrix.language }} - name: Build policy controller for CodeQL run: | make policy-controller - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5 ================================================ FILE: .github/workflows/depsreview.yml ================================================ # # 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: 'Dependency Review' on: [pull_request] permissions: contents: read jobs: dependency-review: name: dependency-review uses: sigstore/community/.github/workflows/reusable-dependency-review.yml@a38887851a12d604b8441ed09e6ebf6b9fe17cbc # main branch 30/Jun/2025 ================================================ FILE: .github/workflows/donotsubmit.yaml ================================================ name: Do Not Submit on: pull_request: branches: [ 'main', 'release-*' ] permissions: read-all jobs: donotsubmit: name: Do Not Submit runs-on: ubuntu-latest steps: - name: Check out code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2 - name: Do Not Submit uses: chainguard-dev/actions/donotsubmit@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 ================================================ FILE: .github/workflows/kind-cluster-image-policy-no-tuf.yaml ================================================ # 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 ClusterImagePolicy TUF disabled on: pull_request: branches: [ 'main', 'release-*' ] defaults: run: shell: bash permissions: read-all jobs: cip-test-no-tuf: name: ClusterImagePolicy e2e tests TUF disabled runs-on: ubuntu-latest strategy: fail-fast: false # Keep running if one leg fails. matrix: k8s-version: - v1.31.x - v1.32.x - v1.33.x - v1.34.x env: KO_DOCKER_REPO: "registry.local:5000/policy-controller" SCAFFOLDING_RELEASE_VERSION: "v0.7.27" 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: './go.mod' check-latest: true # will use the latest release available for ko - uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9 - uses: imranismail/setup-kustomize@53f941b41dca13ed61874bbc6b4b6e1562877530 # v3.0.0 - name: Install yq uses: mikefarah/yq@5a7e72a743649b1b3a47d1a1d8214f3453173c51 # v4.52.4 - name: Setup mirror uses: chainguard-dev/actions/setup-mirror@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 with: mirror: mirror.gcr.io - uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 - name: Install cluster + sigstore uses: sigstore/scaffolding/actions/setup@main with: k8s-version: ${{ matrix.k8s-version}} version: ${{ env.SCAFFOLDING_RELEASE_VERSION }} - name: Install policy-controller env: GIT_HASH: ${{ github.sha }} GIT_VERSION: ci LDFLAGS: "" POLICY_CONTROLLER_YAML: test/kustomize-no-tuf/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-no-tuf | kubectl apply -f - # Wait for the webhook to come up and become Ready kubectl rollout status --timeout 5m --namespace cosign-system deployments/webhook - name: Run Cluster Image Policy Tests that only tests keys, no keyless timeout-minutes: 15 run: | ./test/e2e_test_cluster_image_policy_no_tuf.sh - name: Collect diagnostics if: ${{ failure() }} uses: chainguard-dev/actions/kind-diag@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 ================================================ FILE: .github/workflows/kind-cluster-image-policy-trustroot.yaml ================================================ # 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 TrustRoot - Bring your own keys 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 TrustRoot - Bring Your Own Keys runs-on: ubuntu-latest strategy: fail-fast: false # Keep running if one leg fails. matrix: k8s-version: - v1.31.x - v1.32.x - v1.33.x - v1.34.x script: - repository - remote - bring_own_keys env: KO_DOCKER_REPO: "registry.local:5000/policy-controller" SCAFFOLDING_RELEASE_VERSION: "v0.7.27" 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: './go.mod' check-latest: true # will use the latest release available for ko - uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9 - uses: imranismail/setup-kustomize@53f941b41dca13ed61874bbc6b4b6e1562877530 # v3.0.0 - name: Install yq uses: mikefarah/yq@5a7e72a743649b1b3a47d1a1d8214f3453173c51 # v4.52.4 - name: Setup mirror uses: chainguard-dev/actions/setup-mirror@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 with: mirror: mirror.gcr.io - uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 - name: Install cluster + sigstore uses: sigstore/scaffolding/actions/setup@main with: k8s-version: ${{ matrix.k8s-version}} version: ${{ env.SCAFFOLDING_RELEASE_VERSION }} # Install policy-controller that does not have TUF embedded or installed. - name: Install policy-controller env: GIT_HASH: ${{ github.sha }} GIT_VERSION: ci LDFLAGS: "" POLICY_CONTROLLER_YAML: test/kustomize-no-tuf/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-no-tuf | 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 Trustroot Tests that tests with different TUF configurations timeout-minutes: 5 run: | ./test/e2e_test_cluster_image_policy_with_trustroot_${{ matrix.script }}.sh - name: Collect diagnostics if: ${{ failure() }} uses: chainguard-dev/actions/kind-diag@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 ================================================ FILE: .github/workflows/kind-cluster-image-policy-tsa.yaml ================================================ # 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 TSA 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 TrustRoot - Bring Your Own Keys runs-on: ubuntu-latest strategy: fail-fast: false # Keep running if one leg fails. matrix: k8s-version: - v1.31.x - v1.32.x - v1.33.x - v1.34.x env: KO_DOCKER_REPO: "registry.local:5000/policy-controller" SCAFFOLDING_RELEASE_VERSION: "v0.7.27" 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: './go.mod' check-latest: true # will use the latest release available for ko - uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9 - uses: imranismail/setup-kustomize@53f941b41dca13ed61874bbc6b4b6e1562877530 # v3.0.0 - name: Install yq uses: mikefarah/yq@5a7e72a743649b1b3a47d1a1d8214f3453173c51 # v4.52.4 - name: Setup mirror uses: chainguard-dev/actions/setup-mirror@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 with: mirror: mirror.gcr.io - uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 # 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 }} # Install policy-controller that does not have TUF embedded or installed. - name: Install policy-controller env: GIT_HASH: ${{ github.sha }} GIT_VERSION: ci LDFLAGS: "" POLICY_CONTROLLER_YAML: test/kustomize-no-tuf/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-no-tuf | 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: Checkout TSA for testing. uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # 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 TSA Tests timeout-minutes: 5 run: | ./test/e2e_test_cluster_image_policy_with_tsa.sh - name: Collect diagnostics if: ${{ failure() }} uses: chainguard-dev/actions/kind-diag@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 ================================================ FILE: .github/workflows/kind-cluster-image-policy.yaml ================================================ # 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 ClusterImagePolicy on: pull_request: branches: [ 'main', 'release-*' ] defaults: run: shell: bash permissions: read-all jobs: cip-test: name: ClusterImagePolicy e2e tests runs-on: ubuntu-latest strategy: fail-fast: false # Keep running if one leg fails. matrix: k8s-version: - v1.31.x - v1.32.x - v1.33.x - v1.34.x script: - cluster_image_policy - cluster_image_policy_with_attestations - cluster_image_policy_with_oci11_attestations - cluster_with_scalable - cluster_image_policy_with_warn - cluster_image_policy_with_source - cluster_image_policy_with_fetch_config_file - cluster_image_policy_with_include_spec - cluster_image_policy_with_include_objectmeta - cluster_image_policy_with_attestations_rego - cluster_image_policy_with_include_typemeta - cluster_image_policy_from_configmap_with_fetch_config_file - cluster_image_policy_from_url env: KO_DOCKER_REPO: "registry.local:5000/policy-controller" SCAFFOLDING_RELEASE_VERSION: "v0.7.27" 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: './go.mod' check-latest: true # will use the latest release available for ko - uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9 - uses: imranismail/setup-kustomize@53f941b41dca13ed61874bbc6b4b6e1562877530 # v3.0.0 - name: Install yq uses: mikefarah/yq@5a7e72a743649b1b3a47d1a1d8214f3453173c51 # v4.52.4 - name: Setup mirror uses: chainguard-dev/actions/setup-mirror@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 with: mirror: mirror.gcr.io - uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 - name: Install cluster + sigstore uses: sigstore/scaffolding/actions/setup@main with: k8s-version: ${{ matrix.k8s-version}} version: ${{ env.SCAFFOLDING_RELEASE_VERSION }} - name: Copy TUF root to policy-controller namespace run: | kubectl create ns cosign-system kubectl -n tuf-system get secrets tuf-root -oyaml | sed 's/namespace: .*/namespace: cosign-system/' | kubectl create -f - echo "TUF_ROOT_FILE=./root.json" >> $GITHUB_ENV - name: Install policy-controller env: GIT_HASH: ${{ github.sha }} GIT_VERSION: ci LDFLAGS: "" POLICY_CONTROLLER_YAML: test/kustomize/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 | kubectl apply -f - # Wait for the webhook to come up and become Ready kubectl rollout status --timeout 5m --namespace cosign-system deployments/webhook # And make sure everything is up. kubectl wait deployment -n cosign-system --for condition=Available=True --timeout=90s --all sleep 10 - name: Run Cluster Image Policy Tests timeout-minutes: 15 run: | ./test/e2e_test_${{ matrix.script }}.sh - name: Make sure validatingwebookconfiguration contains no status subresources run: | if kubectl get validatingwebhookconfigurations -oyaml policy.sigstore.dev | grep -q status; then echo Found status resources in the webhook configuration exit 1 fi - name: Collect diagnostics if: ${{ failure() }} uses: chainguard-dev/actions/kind-diag@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 ================================================ FILE: .github/workflows/kind-e2e-cosigned.yaml ================================================ # Copyright 2021 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: Policy Controller KinD E2E on: pull_request: branches: - 'main' permissions: {} jobs: e2e-tests: name: e2e tests runs-on: ubuntu-latest permissions: contents: read # For checking out the code. strategy: fail-fast: false # Keep running if one leg fails. matrix: k8s-version: - v1.31.x - v1.32.x - v1.33.x - v1.34.x env: # https://github.com/google/go-containerregistry/pull/125 allows insecure registry for # '*.local' hostnames. REGISTRY_NAME: registry.local REGISTRY_PORT: 5000 INSECURE_REGISTRY_NAME: insecure-registry.notlocal INSECURE_REGISTRY_PORT: 5001 KO_DOCKER_REPO: registry.local:5000/policy-controller 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: './go.mod' check-latest: true - uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9 - uses: imranismail/setup-kustomize@53f941b41dca13ed61874bbc6b4b6e1562877530 # v3.0.0 - uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 # v3.9.2 - name: Setup mirror uses: chainguard-dev/actions/setup-mirror@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 with: mirror: mirror.gcr.io - name: Setup kind cluster uses: chainguard-dev/actions/setup-kind@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 with: k8s-version: ${{ matrix.k8s-version }} cluster-suffix: c${{ github.run_id }}.local - name: Setup local insecure registry run: | # Create a self-signed SSL cert mkdir -p insecure-certs openssl req \ -subj "/C=US/ST=WA/L=Flavorton/O=Tests-R-Us/OU=Dept. of Insecurity/CN=example.com/emailAddress=testing@example.com" \ -newkey rsa:4096 -nodes -sha256 -keyout insecure-certs/domain.key \ -x509 -days 365 -out insecure-certs/domain.crt # Run a registry. docker run -d --restart=always \ --name $INSECURE_REGISTRY_NAME \ -v "$(pwd)"/insecure-certs:/insecure-certs \ -e REGISTRY_HTTP_ADDR=0.0.0.0:$INSECURE_REGISTRY_PORT \ -e REGISTRY_HTTP_TLS_CERTIFICATE=/insecure-certs/domain.crt \ -e REGISTRY_HTTP_TLS_KEY=/insecure-certs/domain.key \ -p $INSECURE_REGISTRY_PORT:$INSECURE_REGISTRY_PORT \ registry:2 # Connect the registry to the KinD network. docker network connect "kind" $INSECURE_REGISTRY_NAME # Make the $INSECURE_REGISTRY_NAME -> 127.0.0.1, to tell `ko` to publish to # local registry, even when pushing $INSECURE_REGISTRY_NAME:$INSECURE_REGISTRY_NAME/some/image sudo echo "127.0.0.1 $INSECURE_REGISTRY_NAME" | sudo tee -a /etc/hosts - name: Install policy-controller env: GIT_HASH: ${{ github.sha }} GIT_VERSION: ci LDFLAGS: "" POLICY_CONTROLLER_YAML: policy-controller-e2e.yaml KO_PREFIX: registry.local:5000/policy-controller POLICY_CONTROLLER_ARCHS: linux/amd64 run: | make ko-policy-controller kubectl apply -f policy-controller-e2e.yaml # Wait for the webhook to come up and become Ready kubectl rollout status --timeout 5m --namespace cosign-system deployments/webhook kubectl wait deployment -n cosign-system --for condition=Available=True --timeout=90s --all - name: Run Image Policy Tests run: | ./test/e2e_test_policy_crd.sh - name: Run Policy Controller Tests run: | ./test/e2e_test_policy_controller.sh - name: Collect diagnostics if: ${{ failure() }} uses: chainguard-dev/actions/kind-diag@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 ================================================ FILE: .github/workflows/kind-e2e-trustroot-crd.yaml ================================================ # 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: TrustRoot CRD KinD E2E on: pull_request: branches: - 'main' permissions: {} jobs: e2e-crd-tests: name: e2e CRD tests runs-on: ubuntu-latest permissions: contents: read # For checking out the code. strategy: fail-fast: false # Keep running if one leg fails. matrix: k8s-version: - v1.31.x - v1.32.x - v1.33.x - v1.34.x env: # https://github.com/google/go-containerregistry/pull/125 allows insecure registry for # '*.local' hostnames. REGISTRY_NAME: registry.local REGISTRY_PORT: 5000 INSECURE_REGISTRY_NAME: insecure-registry.notlocal INSECURE_REGISTRY_PORT: 5001 KO_DOCKER_REPO: registry.local:5000/policy-controller 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: './go.mod' check-latest: true - uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9 - uses: imranismail/setup-kustomize@53f941b41dca13ed61874bbc6b4b6e1562877530 # v3.0.0 - uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 - name: Setup mirror uses: chainguard-dev/actions/setup-mirror@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 with: mirror: mirror.gcr.io - name: Setup kind cluster uses: chainguard-dev/actions/setup-kind@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 with: k8s-version: ${{ matrix.k8s-version }} cluster-suffix: c${{ github.run_id }}.local - name: Install policy-controller env: GIT_HASH: ${{ github.sha }} GIT_VERSION: ci LDFLAGS: "" POLICY_CONTROLLER_YAML: policy-controller-e2e.yaml KO_PREFIX: registry.local:5000/policy-controller POLICY_CONTROLLER_ARCHS: linux/amd64 run: | make ko-policy-controller kubectl apply -f policy-controller-e2e.yaml # Wait for the webhook to come up and become Ready kubectl rollout status --timeout 5m --namespace cosign-system deployments/webhook kubectl wait deployment -n cosign-system --for condition=Available=True --timeout=90s --all - name: Run TrustRoot CRD e2e tests run: | ./test/e2e_test_trustroot_crd.sh - name: Collect diagnostics if: ${{ failure() }} uses: chainguard-dev/actions/kind-diag@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 ================================================ FILE: .github/workflows/lint.yaml ================================================ name: golangci-lint on: push: branches: - main pull_request: permissions: {} jobs: golangci: name: lint runs-on: ubuntu-latest permissions: contents: read pull-requests: read steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: './go.mod' - name: golangci-lint uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0 with: version: v2.6 ================================================ FILE: .github/workflows/milestone.yaml ================================================ name: Milestone on: pull_request_target: types: [closed] branches: - main jobs: milestone: runs-on: ubuntu-latest permissions: actions: none checks: none contents: read deployments: none issues: write packages: none pull-requests: write repository-projects: none security-events: none statuses: none steps: - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: script: | if (!context.payload.pull_request.merged) { console.log('PR was not merged, skipping.'); return; } if (!!context.payload.pull_request.milestone) { console.log('PR has existing milestone, skipping.'); return; } milestones = await github.rest.issues.listMilestones({ owner: context.repo.owner, repo: context.repo.repo, state: 'open', sort: 'due_on', direction: 'asc' }) if (milestones.data.length === 0) { console.log('There are no milestones, skipping.'); return; } await github.rest.issues.update({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.pull_request.number, milestone: milestones.data[0].number }); ================================================ FILE: .github/workflows/policy-tester-examples.yml ================================================ # # 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: Verify examples using policy-tester on: workflow_dispatch: push: branches: ['main', 'release-*'] pull_request: jobs: verify: runs-on: ubuntu-latest permissions: id-token: write contents: read env: GOPATH: ${{ github.workspace }} COSIGN_YES: "true" steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: ./src/github.com/${{ github.repository }} fetch-depth: 0 - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: './src/github.com/${{ github.repository }}/go.mod' check-latest: true - name: Build the policy-tester CLI working-directory: ./src/github.com/${{ github.repository }} run: | make policy-tester - uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 - name: Setup local registry run: | docker run -d --restart=always \ --name registry.local \ -e REGISTRY_HTTP_ADDR=0.0.0.0:5000 \ -p 5000:5000 \ registry:2 - name: Example (custom-key-attestation-sbom-spdxjson) working-directory: ./src/github.com/${{ github.repository }}/examples run: | REF="localhost:5000/examples/custom-key-attestation-sbom-spdxjson" # Push an image docker pull alpine docker tag alpine "${REF}" docker push "${REF}" # Attach attestation to image cosign attest --yes --type spdxjson \ --predicate sboms/example.spdx.json \ --key keys/cosign.key \ "${REF}" # Verify the attestation cosign verify-attestation \ --type spdxjson \ --key keys/cosign.pub \ "${REF}" # Ensure the image satisfies the policy ../policy-tester \ --policy policies/custom-key-attestation-sbom-spdxjson.yaml \ --image "${REF}" # Make sure we can't run Jobs, exercise metadata CIP matching. - name: Example (verify CIP level typemeta policy failure) working-directory: ./src/github.com/${{ github.repository }} run: | REF="ghcr.io/sigstore/timestamp-server@sha256:dcf2f3a640bfb0a5d17aabafb34b407fe4403363c715718ab305a62b3606540d" # Ensure the image does not satisfy the policy if ./policy-tester \ --policy examples/policies/allow-only-pods.yaml \ --image "${REF}" \ --resource test/testdata/resources/job.yaml ; then echo Failed to block Job from running exit 1 fi # Make sure we can't run Pods, exercise metadata CIP matching. - name: Example (verify CIP level typemeta policy success) working-directory: ./src/github.com/${{ github.repository }} run: | REF="ghcr.io/sigstore/timestamp-server@sha256:dcf2f3a640bfb0a5d17aabafb34b407fe4403363c715718ab305a62b3606540d" # Ensure the image satisfies the policy ./policy-tester \ --policy examples/policies/allow-only-pods.yaml \ --image "${REF}" \ --resource test/testdata/resources/pod.yaml # This example requires public Fulcio, only run on push to main - if: ${{ github.event_name == 'push' }} name: Example (keyless-attestation-sbom-spdxjson) working-directory: ./src/github.com/${{ github.repository }}/examples run: | REF="localhost:5000/examples/keyless-attestation-sbom-spdxjson" # Push an image docker pull alpine docker tag alpine "${REF}" docker push "${REF}" # Attach attestation to image cosign attest --yes --type spdxjson \ --predicate sboms/example.spdx.json \ "${REF}" # Ensure the image satisfies the policy ../policy-tester \ --policy policies/keyless-attestation-sbom-spdxjson.yaml \ --image "${REF}" # This example requires public Fulcio, only run on push to main - if: ${{ github.event_name == 'push' }} name: Example (signed-by-github-actions) working-directory: ./src/github.com/${{ github.repository }}/examples run: | REF="localhost:5000/examples/signed-by-github-actions" # Push an image docker pull alpine docker tag alpine "${REF}" docker push "${REF}" # Sign image cosign sign "${REF}" # Ensure the image satisfies the policy ../policy-tester \ --policy policies/signed-by-github-actions.yaml \ --image "${REF}" ================================================ FILE: .github/workflows/release-snapshot.yaml ================================================ name: snapshot on: pull_request: permissions: contents: read jobs: snapshot: runs-on: ubuntu-latest steps: - uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 with: android: true dotnet: true haskell: true large-packages: true docker-images: true swap-storage: true - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: './go.mod' check-latest: true - uses: anchore/sbom-action/download-syft@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0 - uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9 - name: Set LDFLAGS id: ldflags run: | source ./release/ldflags.sh goflags=$(ldflags) echo "GO_FLAGS="${goflags}"" >> "$GITHUB_ENV" - name: Run GoReleaser id: run-goreleaser uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7.0.0 with: version: latest args: release --snapshot --clean --timeout 120m --skip=sign env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} LDFLAGS: ${{ env.GO_FLAGS }} ================================================ FILE: .github/workflows/release.yaml ================================================ name: Cut Release on: push: tags: - "v*" concurrency: cut-release permissions: contents: write # needed to write releases id-token: write # needed for keyless signing packages: write # needed for pushing the images to ghcr.io jobs: release: outputs: hashes: ${{ steps.hash.outputs.hashes }} tag_name: ${{ steps.tag.outputs.tag_name }} runs-on: ubuntu-latest steps: - uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 with: android: true dotnet: true haskell: true large-packages: true docker-images: true swap-storage: true - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: './go.mod' check-latest: true - uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 - uses: anchore/sbom-action/download-syft@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0 - uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9 - name: Set up Cloud SDK uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 with: workload_identity_provider: 'projects/498091336538/locations/global/workloadIdentityPools/githubactions/providers/sigstore-policy-controller' service_account: 'gha-policy-controller@projectsigstore.iam.gserviceaccount.com' - name: 'Set up Cloud SDK' uses: google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db # v3.0.1 - name: creds run: gcloud auth configure-docker --quiet - name: Set LDFLAGS id: ldflags run: | source ./release/ldflags.sh goflags=$(ldflags) echo "GO_FLAGS="${goflags}"" >> "$GITHUB_ENV" - name: Set tag output id: tag run: echo "tag_name=${GITHUB_REF#refs/*/}" >> "$GITHUB_OUTPUT" - name: Run GoReleaser id: run-goreleaser uses: goreleaser/goreleaser-action@ec59f474b9834571250b370d4735c50f8e2d1e29 # v7.0.0 with: version: latest args: release --clean --timeout 120m --parallelism 1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} LDFLAGS: ${{ env.GO_FLAGS }} - name: Generate subject id: hash env: ARTIFACTS: "${{ steps.run-goreleaser.outputs.artifacts }}" run: | set -euo pipefail checksum_file=$(echo "$ARTIFACTS" | jq -r '.[] | select (.type=="Checksum") | .path') echo "hashes=$(cat $checksum_file | base64 -w0)" >> "$GITHUB_OUTPUT" - name: build images run: | make build-sign-release-images env: LDFLAGS: ${{ env.GO_FLAGS }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: copy-signed-release-to-ghcr run: make copy-signed-release-to-ghcr || true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} provenance: needs: [release] permissions: actions: read # To read the workflow path. id-token: write # To sign the provenance. contents: write # To add assets to a release. uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0 with: base64-subjects: "${{ needs.release.outputs.hashes }}" upload-assets: true # upload to a new release upload-tag-name: "${{ needs.release.outputs.tag_name }}" ================================================ FILE: .github/workflows/scorecard_action.yml ================================================ name: Scorecards supply-chain security on: # Only the default branch is supported. branch_protection_rule: schedule: # Weekly on Saturdays. - cron: '30 1 * * 6' push: branches: [ main ] # Declare default permissions as read only. permissions: read-all jobs: analysis: name: Scorecards analysis runs-on: ubuntu-latest permissions: # Needed to upload the results to code-scanning dashboard. security-events: write actions: read contents: read id-token: write steps: - name: "Checkout code" uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: persist-credentials: false - name: "Run analysis" uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 with: results_file: results.sarif results_format: sarif # Read-only PAT token. To create it, # follow the steps in https://github.com/ossf/scorecard-action#pat-token-creation. repo_token: ${{ secrets.SCORECARD_TOKEN }} # Publish the results for public repositories to enable scorecard badges. For more details, see # https://github.com/ossf/scorecard-action#publishing-results. # For private repositories, `publish_results` will automatically be set to `false`, regardless # of the value entered here. publish_results: true # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: SARIF file path: results.sarif retention-days: 5 # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" uses: github/codeql-action/upload-sarif@38697555549f1db7851b81482ff19f1fa5c4fedc # v3.29.5 with: sarif_file: results.sarif ================================================ FILE: .github/workflows/style.yaml ================================================ name: Code Style on: pull_request: branches: [ 'main', 'release-*' ] permissions: read-all jobs: gofmt: name: check gofmt runs-on: ubuntu-latest steps: - name: Check out code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Go uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: './go.mod' check-latest: true - uses: chainguard-dev/actions/gofmt@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 with: args: -s goimports: name: check goimports runs-on: ubuntu-latest steps: - name: Check out code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Go uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: './go.mod' check-latest: true - uses: chainguard-dev/actions/goimports@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 ================================================ FILE: .github/workflows/tests.yaml ================================================ # Copyright 2021 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: CI-Tests on: workflow_dispatch: push: branches: ['main', 'release-*'] pull_request: permissions: read-all jobs: unit-tests: name: Run unit tests permissions: contents: read runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest] env: OS: ${{ matrix.os }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # https://github.com/mvdan/github-actions-golang#how-do-i-set-up-caching-between-builds - uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: # In order: # * Module download cache # * Build cache (Linux) path: | ~/go/pkg/mod ~/.cache/go-build ~/Library/Caches/go-build %LocalAppData%\go-build key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: './go.mod' check-latest: true - name: Run Go tests run: go test -covermode atomic -coverprofile coverage.txt $(go list ./... | grep -v third_party/) - name: Upload Coverage Report uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad # v5.5.3 with: env_vars: OS - name: Run Go tests w/ `-race` if: ${{ runner.os == 'Linux' }} run: go test -race $(go list ./... | grep -v third_party/) license-check: name: license boilerplate check runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: './go.mod' check-latest: true - name: Install addlicense run: go install github.com/google/addlicense@latest - name: Check license headers run: | set -e addlicense -check -l apache -c 'The Sigstore Authors' -ignore "third_party/**" -v * ================================================ FILE: .github/workflows/verify-codegen.yaml ================================================ # # 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: Codegen on: workflow_dispatch: push: branches: ['main', 'release-*'] pull_request: permissions: read-all jobs: verify: name: Verify codegen runs-on: ubuntu-latest env: GOPATH: ${{ github.workspace }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: ./src/github.com/${{ github.repository }} fetch-depth: 0 - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: './src/github.com/${{ github.repository }}/go.mod' check-latest: true - shell: bash working-directory: ./src/github.com/${{ github.repository }} run: | ./hack/update-codegen.sh # For whatever reason running this makes it not complain... git status - uses: chainguard-dev/actions/nodiff@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 with: path: ./src/github.com/${{ github.repository }} fixup-command: "./hack/update-codegen.sh" ================================================ FILE: .github/workflows/verify-docs.yaml ================================================ # # 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: API Docs Generator on: workflow_dispatch: push: branches: ['main', 'release-*'] pull_request: permissions: read-all jobs: verify-docs: name: Verify API docs runs-on: ubuntu-latest env: GOPATH: ${{ github.workspace }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: ./src/github.com/${{ github.repository }} fetch-depth: 0 - uses: actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0 with: go-version-file: './src/github.com/${{ github.repository }}/go.mod' check-latest: true - shell: bash working-directory: ./src/github.com/${{ github.repository }} run: | make docs # For whatever reason running this makes it not complain... git status - uses: chainguard-dev/actions/nodiff@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 with: path: ./src/github.com/${{ github.repository }} fixup-command: "make docs" ================================================ FILE: .github/workflows/whitespace.yaml ================================================ name: Whitespace on: pull_request: branches: [ 'main', 'release-*' ] permissions: read-all jobs: whitespace: name: Check Whitespace runs-on: ubuntu-latest steps: - name: Check out code uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: chainguard-dev/actions/trailing-space@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 if: ${{ always() }} - uses: chainguard-dev/actions/eof-newline@d67380d0b02c09412f8e17f660ec48870bd89e6e # v1.6.9 if: ${{ always() }} ================================================ FILE: .gitignore ================================================ # Binaries for programs and plugins .DS_STORE *.exe *.exe~ *.dll *.so *.dylib # Test binary, built with `go test -c` *.test # Output of the go coverage tool, specifically when used with LiteIDE *.out # Dependency directories (remove the comment below to include it) # vendor/ # cosign stuff /cosign* .vscode .idea # fuzzing artifacts *.libfuzzer *fuzz.a bin* dist/ policyControllerImagerefs **verify-experimental* policy-controller policy-tester # Vim *.swp gha-creds-*.json # Kind cluster configuration produced by the local-dev tool kind.yaml ================================================ FILE: .golangci.yml ================================================ # # Copyright 2021 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. version: "2" run: issues-exit-code: 1 linters: enable: - asciicheck - errorlint - gocritic - gosec - importas - misspell - prealloc - revive - staticcheck - tparallel - unconvert - unparam - whitespace settings: revive: rules: - name: dot-imports arguments: - allowedPackages: - knative.dev/pkg/configmap/testing - knative.dev/pkg/reconciler/testing - github.com/sigstore/policy-controller/pkg/reconciler/testing/v1alpha1 exclusions: generated: lax presets: - comments - common-false-positives - legacy - std-error-handling rules: - linters: - errcheck - gosec path: _test\.go paths: - ^third_party/ - ^examples/ issues: max-issues-per-linter: 0 max-same-issues: 0 formatters: enable: - gofmt - goimports exclusions: generated: lax paths: - ^third_party/ - ^examples/ ================================================ FILE: .goreleaser.yaml ================================================ project_name: policy-controller version: 2 env: - GO111MODULE=on - COSIGN_YES=true before: hooks: - go mod tidy - /bin/bash -c 'if [ -n "$(git --no-pager diff --exit-code go.mod go.sum)" ]; then exit 1; fi' builds: - id: tester binary: tester-{{ .Os }}-{{ .Arch }} no_unique_dist_dir: true main: ./cmd/tester flags: - -trimpath mod_timestamp: '{{ .CommitTimestamp }}' goos: - linux - darwin - windows goarch: - amd64 - arm64 - arm - s390x - ppc64le goarm: - 7 ignore: - goos: windows goarch: arm64 - goos: windows goarch: arm - goos: windows goarch: s390x - goos: windows goarch: ppc64le ldflags: - "{{ .Env.LDFLAGS }}" env: - CGO_ENABLED=0 signs: # Keyless - id: tester signature: "${artifact}-keyless.sig" certificate: "${artifact}-keyless.pem" cmd: cosign args: ["sign-blob", "--output-signature", "${artifact}-keyless.sig", "--output-certificate", "${artifact}-keyless.pem", "${artifact}"] artifacts: binary - id: checksum-keyless signature: "${artifact}-keyless.sig" certificate: "${artifact}-keyless.pem" cmd: cosign args: ["sign-blob", "--output-signature", "${artifact}-keyless.sig", "--output-certificate", "${artifact}-keyless.pem", "${artifact}"] artifacts: checksum archives: - format: binary name_template: "{{ .Binary }}" allow_different_binary_count: true checksum: name_template: "{{ .ProjectName }}_checksums.txt" snapshot: version_template: SNAPSHOT-{{ .ShortCommit }} release: prerelease: allow # remove this when we start publishing non-prerelease or set to auto github: owner: sigstore name: policy-controller footer: | ### Thanks to all contributors! extra_files: - glob: "./policy-controller*.yaml" ================================================ FILE: .ko.yaml ================================================ # # Copyright 2021 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. defaultBaseImage: cgr.dev/chainguard/static:latest builds: - id: policy-controller dir: . main: ./cmd/webhook env: - CGO_ENABLED=0 flags: - -trimpath - --tags - "{{ .Env.GIT_HASH }}" - --tags - "{{ .Env.GIT_VERSION }}" ldflags: - -extldflags "-static" - "{{ .Env.LDFLAGS }}" ================================================ FILE: CHANGELOG.md ================================================ # v0.12.0 * drop 1.27/28 and add 1.30/31/32 k8s * fix post submit job * Use v0.7.18 for scaffolding, update k8s versions to test with ## Contributors * Carlos Tadeu Panato Junior * Ville Aikas # v0.1.0 ## Enhancements * Refactor entire policy validation into ValidatePolicy. * Set reinvocationPolicy to 'IfNeeded' for the tag resolver webhook * Add policy-tester CLI for testing ClusterImagePolicies * (tester) Validate CIP before using it. * (tester) call SetDefaults on cip before conversion * remove v1.21 k8s which is deprecated and add v1.24 * chore: do not fail to verify signed images if the secret-name flag is not set ## Bug fixes * Fix issue #38. Do not block status updates. * Avoid test race condition. * Fix https://github.com/sigstore/cosign/issues/1653 * Allow for @ symbol on globs to support image refs with digest * Validate globs at admission time. * fix: add missing conversion to CRD * fix: solve vuln from our opa version * Fix issue #24 * Bump some vulnerable dependencies; base on distroless/static ## Others * Bump mikefarah/yq from 4.25.3 to 4.26.1 * Bump actions/dependency-review-action from 2.0.2 to 2.0.4 * Bump google.golang.org/grpc from 1.47.0 to 1.48.0 * Bump github/codeql-action from 2.1.15 to 2.1.16 * Bump actions/cache from 3.0.4 to 3.0.5 * Bump actions/setup-go from 3.2.0 to 3.2.1 * update knative to use v1.5.0 release * update scafolding to use release v0.3.0 * Bump github.com/aws/aws-sdk-go-v2 from 1.16.6 to 1.16.7 * Bump sigstore/cosign-installer from 2.4.0 to 2.4.1 * Bump github.com/aws/aws-sdk-go-v2 from 1.16.5 to 1.16.6 * increase timeout for golangci-lint * Bump github.com/stretchr/testify from 1.7.5 to 1.8.0 * Bump github/codeql-action from 2.1.14 to 2.1.15 * Switch to direct returns * Bump github.com/hashicorp/go-version from 1.5.0 to 1.6.0 * Bump ossf/scorecard-action from 1.1.1 to 1.1.2 * chore: skip secret not found * Bump github.com/stretchr/testify from 1.7.4 to 1.7.5 * Bump mikefarah/yq from 4.25.2 to 4.25.3 * Bump github/codeql-action from 2.1.13 to 2.1.14 * Bump github.com/google/go-containerregistry from 0.9.0 to 0.10.0 * Bump github.com/stretchr/testify from 1.7.2 to 1.7.4 * Bump github/codeql-action from 2.1.12 to 2.1.13 * Bump actions/dependency-review-action from 2.0.1 to 2.0.2 * Bump actions/dependency-review-action from 1.0.2 to 2.0.1 * Update tests for OR behaviour wrt authorities. * remove unused struct from imports * Add policy to make sure signature and attestation is there. * Return authoritymatches before errors. * remove third_party stuff due to mismatch in go version. * Use fulcioroots from sigstore/sigstore * Even if some authority returns err, return any other matching authority results. * Use public fulcio/rekor to make sure things are not there. * hack/update-deps.sh ## Contributors * Carlos Tadeu Panato Junior * Hector Fernandez * Jason Hall * Josh Dolitsky * Matt Moore * Ville Aikas * Vladimir Nachev * cpanato * dependabot[bot] * dlorenc * hectorj2f ================================================ FILE: CODEOWNERS ================================================ # The CODEOWNERS are managed via a GitHub team, but the current list is (in alphabetical order): # # lukehinds ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at . All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: COPYRIGHT.txt ================================================ Copyright 2021 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. ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: Makefile ================================================ # # Copyright 2021 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. # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) ifeq (,$(shell go env GOBIN)) GOBIN=$(shell go env GOPATH)/bin else GOBIN=$(shell go env GOBIN) endif GOFILES ?= $(shell find . -type f -name '*.go' -not -path "./vendor/*") # Set version variables for LDFLAGS PROJECT_ID ?= projectsigstore RUNTIME_IMAGE ?= gcr.io/distroless/static GIT_VERSION ?= $(shell git describe --tags --always --dirty) GIT_HASH ?= $(shell git rev-parse HEAD) DATE_FMT = +%Y-%m-%dT%H:%M:%SZ SOURCE_DATE_EPOCH ?= $(shell git log -1 --pretty=%ct) ifdef SOURCE_DATE_EPOCH BUILD_DATE ?= $(shell date -u -d "@$(SOURCE_DATE_EPOCH)" "$(DATE_FMT)" 2>/dev/null || date -u -r "$(SOURCE_DATE_EPOCH)" "$(DATE_FMT)" 2>/dev/null || date -u "$(DATE_FMT)") else BUILD_DATE ?= $(shell date "$(DATE_FMT)") endif GIT_TREESTATE = "clean" DIFF = $(shell git diff --quiet >/dev/null 2>&1; if [ $$? -eq 1 ]; then echo "1"; fi) ifeq ($(DIFF), 1) GIT_TREESTATE = "dirty" endif POLICY_CONTROLLER_ARCHS?=all LDFLAGS=-buildid= -X sigs.k8s.io/release-utils/version.gitVersion=$(GIT_VERSION) \ -X sigs.k8s.io/release-utils/version.gitCommit=$(GIT_HASH) \ -X sigs.k8s.io/release-utils/version.gitTreeState=$(GIT_TREESTATE) \ -X sigs.k8s.io/release-utils/version.buildDate=$(BUILD_DATE) SRCS = $(shell find cmd -iname "*.go") $(shell find pkg -iname "*.go") GOLANGCI_LINT_DIR = $(shell pwd)/bin GOLANGCI_LINT_BIN = $(GOLANGCI_LINT_DIR)/golangci-lint KO_PREFIX ?= gcr.io/projectsigstore export KO_DOCKER_REPO=$(KO_PREFIX) GHCR_PREFIX ?= ghcr.io/sigstore/policy-controller POLICY_CONTROLLER_YAML ?= policy-controller-$(GIT_VERSION).yaml LATEST_TAG ?= .PHONY: all lint test clean policy-controller cross docs all: policy-controller log-%: @grep -h -E '^$*:.*?## .*$$' $(MAKEFILE_LIST) | \ awk \ 'BEGIN { \ FS = ":.*?## " \ }; \ { \ printf "\033[36m==> %s\033[0m\n", $$2 \ }' .PHONY: checkfmt checkfmt: SHELL := /usr/bin/env bash checkfmt: ## Check formatting of all go files @ $(MAKE) --no-print-directory log-$@ $(shell test -z "$(shell gofmt -l $(GOFILES) | tee /dev/stderr)") $(shell test -z "$(shell goimports -l $(GOFILES) | tee /dev/stderr)") .PHONY: fmt fmt: ## Format all go files @ $(MAKE) --no-print-directory log-$@ goimports -w $(GOFILES) ## Build policy-controller binary .PHONY: policy-controller policy-controller: CGO_ENABLED=0 go build -trimpath -ldflags "$(LDFLAGS)" -o $@ ./cmd/webhook ## Build policy-tester binary .PHONY: policy-tester policy-tester: CGO_ENABLED=0 go build -trimpath -ldflags "$(LDFLAGS)" -o $@ ./cmd/tester ## Build local-dev binary .PHONY: local-dev local-dev: CGO_ENABLED=0 go build -trimpath -ldflags "$(LDFLAGS)" -o bin/$@ ./cmd/local-dev ##################### # lint / test section ##################### golangci-lint: rm -f $(GOLANGCI_LINT_BIN) || : set -e ;\ GOBIN=$(GOLANGCI_LINT_DIR) go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.6.2 ;\ lint: golangci-lint ## Run golangci-lint linter $(GOLANGCI_LINT_BIN) run -n test: go test $(shell go list ./... | grep -v third_party/) clean: rm -rf policy-controller KOCACHE_PATH=/tmp/ko ARTIFACT_HUB_LABELS=--image-label io.artifacthub.package.readme-url="https://raw.githubusercontent.com/sigstore/policy-controller/main/README.md" \ --image-label io.artifacthub.package.license=Apache-2.0 --image-label io.artifacthub.package.vendor=sigstore \ --image-label io.artifacthub.package.version=0.1.0 \ --image-label io.artifacthub.package.name=policy-controller \ --image-label org.opencontainers.image.created=$(BUILD_DATE) \ --image-label org.opencontainers.image.description="Kubernetes webhook for configuring admission policies" \ --image-label io.artifacthub.package.alternative-locations="oci://ghcr.io/sigstore/policy-controller/policy-controller" define create_kocache_path mkdir -p $(KOCACHE_PATH) endef ########## # ko build ########## .PHONY: ko ko: ko-policy-controller .PHONY: ko-policy-controller ko-policy-controller: kustomize-policy-controller # policy-controller LDFLAGS="$(LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) \ KOCACHE=$(KOCACHE_PATH) KO_DOCKER_REPO=$(KO_PREFIX)/policy-controller ko resolve --bare \ --platform=$(POLICY_CONTROLLER_ARCHS) --tags $(GIT_VERSION) --tags $(GIT_HASH)$(LATEST_TAG) \ --image-refs policyControllerImagerefs --filename config/webhook.yaml >> $(POLICY_CONTROLLER_YAML) .PHONY: ko-local ko-local: LDFLAGS="$(LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) \ KOCACHE=$(KOCACHE_PATH) KO_DOCKER_REPO=ko.local ko build --base-import-paths \ --tags $(GIT_VERSION) --tags $(GIT_HASH) \ $(ARTIFACT_HUB_LABELS) \ --platform=all \ github.com/sigstore/policy-controller/cmd/webhook .PHONY: ko-apply ko-apply: LDFLAGS="$(LDFLAGS)" GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) ko apply -Bf config/ .PHONY: kustomize-policy-controller kustomize-policy-controller: kustomize build config/ > $(POLICY_CONTROLLER_YAML) ################## # help ################## help: # Display help @awk -F ':|##' \ '/^[^\t].+?:.*?##/ {\ printf "\033[36m%-30s\033[0m %s\n", $$1, $$NF \ }' $(MAKEFILE_LIST) | sort include release/release.mk include test/ci.mk .PHONY: docs docs: docs/generate-api .PHONY: docs/generate-api docs/generate-api: mkdir -p docs/api-types; \ go run -ldflags "$(GO_LDFLAGS)" ./cmd/api-docs/main.go \ "v1beta1" \ `find ./pkg/apis/policy/v1beta1/ -iname '*types.go' | sort -r | tr '\n' ' '` \ > docs/api-types/index.md; go run -ldflags "$(GO_LDFLAGS)" ./cmd/api-docs/main.go \ "v1alpha1" \ `find ./pkg/apis/policy/v1alpha1/ -iname '*types.go' | sort -r | tr '\n' ' '` \ > docs/api-types/index-v1alpha1.md; .PHONY: generate-testdata generate-testdata: go run hack/gentestdata/gentestdata.go ================================================ FILE: README.md ================================================

Cosign logo

# Policy Controller The `policy-controller` admission controller can be used to enforce policy on a Kubernetes cluster based on verifiable supply-chain metadata from `cosign`. [![Go Report Card](https://goreportcard.com/badge/github.com/sigstore/policy-controller)](https://goreportcard.com/report/github.com/sigstore/policy-controller) [![e2e-tests](https://github.com/sigstore/policy-controller/actions/workflows/kind-e2e-cosigned.yaml/badge.svg)](https://github.com/sigstore/policy-controller/actions/workflows/kind-e2e-cosigned.yaml) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/sigstore/policy-controller/badge)](https://api.securityscorecards.dev/projects/github.com/sigstore/policy-controller) `policy-controller` also resolves the image tags to ensure the image being ran is not different from when it was admitted. See the [installation instructions](https://docs.sigstore.dev/policy-controller/installation) for more information. Today, `policy-controller` can automatically validate signatures and attestations on container images. Enforcement is configured on a per-namespace basis, and multiple keys are supported. We're actively working on more features here. For more information about the `policy-controller`, have a look at our documentation website [here](https://docs.sigstore.dev/policy-controller/overview). ## Examples Please see the [examples/](./examples/) directory for example policies etc. ## Policy Testing This repo includes a `policy-tester` tool which enables checking a policy against various images. In the root of this repo, run the following to build: ``` make policy-tester ``` Then run it pointing to a YAML file containing a ClusterImagePolicy, and an image to evaluate the policy against: ``` (set -o pipefail && \ ./policy-tester \ --policy=test/testdata/policy-controller/tester/cip-public-keyless.yaml \ --image=ghcr.io/sigstore/cosign/cosign:v1.9.0 | jq) ``` ## Local Development You can spin up a local [Kind](https://kind.sigs.k8s.io/) K8s cluster to test local changes to the policy controller using the `local-dev` CLI tool. Build the tool with `make local-dev` and then run it with `./bin/local-dev setup`. It optionally accepts the following: ``` --cluster-name --k8s-version --registry-url ``` You can clean up the cluster with `./bin/local-dev clean --cluster-name=`. You will need to have the following tools installed to use this: - [Docker](https://docs.docker.com/get-docker/) - [kind](https://kind.sigs.k8s.io/) - [ko](https://ko.build/install/) - [kubectl](https://kubernetes.io/docs/tasks/tools/) ### Use local registry If you would like to use the local Kind registry instead of a live one, do not include the `registry-url` flag when calling the CLI. It will default to using the local registry. But before running the CLI, you must add the following line to your `/etc/hosts` file first: `127.0.0.1 registry.local` ## Using Policy Controller with Azure Container Registry (ACR) To allow the webhook to make requests to ACR, you must use one of the following methods to authenticate: 1. Managed identities (used with AKS clusters) 1. Service principals (used with AKS clusters) 1. Pod imagePullSecrets (used with non AKS clusters) See the [official documentation](https://learn.microsoft.com/en-us/azure/container-registry/authenticate-kubernetes-options#scenarios). ### Managed Identities for AKS Clusters See the [official documentation](https://learn.microsoft.com/en-us/azure/aks/cluster-container-registry-integration?toc=%2Fazure%2Fcontainer-registry%2Ftoc.json&bc=%2Fazure%2Fcontainer-registry%2Fbreadcrumb%2Ftoc.json&tabs=azure-cli) for more details. 1. You must enable managed identities for the cluster using the `--enable-managed-identities` flag with either the `az aks create` or `az aks update` commands 1. You must attach the ACR to the AKS cluster using the `--attach-acr` with either the `az aks create` or `az aks update` commands. See [here](https://learn.microsoft.com/en-us/azure/aks/cluster-container-registry-integration?toc=%2Fazure%2Fcontainer-registry%2Ftoc.json&bc=%2Fazure%2Fcontainer-registry%2Fbreadcrumb%2Ftoc.json&tabs=azure-cli#create-a-new-aks-cluster-and-integrate-with-an-existing-acr) for more details 1. You must set the `AZURE_CLIENT_ID` environment variable to the managed identity's client ID. 1. You must set the `AZURE_TENANT_ID` environment variable to the Azure tenant the managed identity resides in. These will detected by the Azure credential manager. When you create a cluster that has managed identities enabled, a user assigned managed identity called `-agentpool`. Use this identity's client ID when setting `AZURE_CLIENT_ID`. Make sure the ACR is attached to your cluster. #### Installing Policy Controller locally from this repository If you are deploying policy-controller directly from this repository with `make ko-apply`, you will need to add `AZURE_CLIENT_ID` and `AZURE_TENANT_ID` to the list of environment variables in the [webhook deployment configuration](config/webhook.yaml). #### Installing Policy Controller from the Helm chart You can provide the managed identity's client ID as a custom environment variable when installing the Helm chart: ```bash helm install policy-controller sigstore/policy-controller --version 0.9.0 \ --set webhook.env.AZURE_CLIENT_ID=my-managed-id-client-id,webhook.env.AZURE_TENANT_ID=tenant-id ``` ### Service Principals for AKS Clusters #### Installing Policy Controller from the Helm chart You should be able to provide the service principal client ID and tenant ID as a workload identity annotations: ```bash helm upgrade --install policy-controller sigstore/policy-controller --version 0.9.0 \ --set-json webhook.serviceAccount.annotations="{\"azure.workload.identity/client-id\": \"${SERVICE_PRINCIPAL_CLIENT_ID}\", \"azure.workload.identity/tenant-id\": \"${TENANT_ID}\"}" ``` ## Support Policy This policy-controller's versions are able to run in the following versions of Kubernetes: | | policy-controller `> 0.2.x` | policy-controller `> 0.10.x` | |---|:---:|:---:| | Kubernetes 1.23 | ✓ | | | Kubernetes 1.24 | ✓ | | | Kubernetes 1.25 | ✓ | | | Kubernetes 1.27 | | ✓ | | Kubernetes 1.28 | | ✓ | | Kubernetes 1.29 | | ✓ | note: not fully tested yet, but can be installed ## Release Cadence We are intending to move to a monthly cadence for minor releases. Minor releases will be published around the beginning of the month. We may cut a patch release instead, if the changes are small enough not to warrant a minor release. We will also cut patch releases periodically as needed to address bugs. ## Security Should you discover any security issues, please refer to Sigstore's [security policy](https://github.com/sigstore/policy-controller/security/policy). ================================================ FILE: cmd/api-docs/main.go ================================================ // // Copyright 2021 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. package main import ( "bytes" "fmt" "go/ast" "go/doc" "go/parser" "go/token" "os" "reflect" "strings" "text/template" ) const ( headerTemplate = ` # API Documentation ({{ .Version }}) > This document is automatically generated from the API definition in the code. ` ) var ( links = map[string]string{ "metav1.ObjectMeta": "https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta", "metav1.ListMeta": "https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#listmeta-v1-meta", "metav1.LabelSelector": "https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#labelselector-v1-meta", "metav1.GroupVersionResource": "https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#groupversionresource-v1-meta", "v1.SecretReference": "https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#secretreference-v1-core", "v1.LocalObjectReference": "https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#localobjectreference-v1-core", } selfLinks = map[string]string{} ) func main() { printAPIDocs(os.Args[1], os.Args[2:]) } func toSectionLink(name string) string { name = strings.ToLower(name) name = strings.ReplaceAll(name, " ", "-") return name } func printTOC(types []KubeTypes) { fmt.Printf("\n## Table of Contents\n") for _, t := range types { strukt := t[0] if len(t) > 1 { fmt.Printf("* [%s](#%s)\n", strukt.Name, toSectionLink(strukt.Name)) } } } func printAPIDocs(version string, paths []string) { header := struct { Version string }{ Version: version, } t, err := template.New("header").Parse(headerTemplate) if err != nil { panic(err) } err = t.Execute(os.Stdout, header) if err != nil { panic(err) } types := ParseDocumentationFrom(paths) for _, t := range types { strukt := t[0] selfLinks[strukt.Name] = "#" + strings.ToLower(strukt.Name) } // we need to parse once more to now add the self links types = ParseDocumentationFrom(paths) printTOC(types) for _, t := range types { strukt := t[0] fmt.Printf("\n## %s\n\n%s\n\n", strukt.Name, strukt.Doc) if len(t) > 1 { fmt.Println("| Field | Description | Scheme | Required |") fmt.Println("| ----- | ----------- | ------ | -------- |") fields := t[1:] for _, f := range fields { fmt.Println("|", f.Name, "|", f.Doc, "|", f.Type, "|", f.Mandatory, "|") } fmt.Println("") fmt.Println("[Back to TOC](#table-of-contents)") } } } // Pair of strings. We keed the name of fields and the doc type Pair struct { Name, Doc, Type string Mandatory bool } // KubeTypes is an array to represent all available types in a parsed file. [0] is for the type itself type KubeTypes []Pair // ParseDocumentationFrom gets all types' documentation and returns them as an // array. Each type is again represented as an array (we have to use arrays as we // need to be sure for the order of the fields). This function returns fields and // struct definitions that have no documentation as {name, ""}. func ParseDocumentationFrom(srcs []string) []KubeTypes { var docForTypes []KubeTypes for _, src := range srcs { pkg := astFrom(src) if pkg == nil { continue } for _, kubType := range pkg.Types { if structType, ok := kubType.Decl.Specs[0].(*ast.TypeSpec).Type.(*ast.StructType); ok { var ks KubeTypes ks = append(ks, Pair{kubType.Name, fmtRawDoc(kubType.Doc), "", false}) for _, field := range structType.Fields.List { typeString := fieldType(field.Type) fieldMandatory := fieldRequired(field) if n := fieldName(field); n != "-" { fieldDoc := fmtRawDoc(field.Doc.Text()) ks = append(ks, Pair{n, fieldDoc, typeString, fieldMandatory}) } } docForTypes = append(docForTypes, ks) } } } return docForTypes } func astFrom(filePath string) *doc.Package { fset := token.NewFileSet() m := make(map[string]*ast.File) f, err := parser.ParseFile(fset, filePath, nil, parser.ParseComments) if err != nil { fmt.Printf("failed to parse file %q: %v\n", filePath, err) return nil } m[filePath] = f apkg, _ := ast.NewPackage(fset, m, nil, nil) //nolint:staticcheck return doc.New(apkg, "", 0) } func fmtRawDoc(rawDoc string) string { var buffer bytes.Buffer delPrevChar := func() { if buffer.Len() > 0 { buffer.Truncate(buffer.Len() - 1) // Delete the last " " or "\n" } } // Ignore all lines after --- rawDoc = strings.Split(rawDoc, "---")[0] for _, line := range strings.Split(rawDoc, "\n") { line = strings.TrimRight(line, " ") leading := strings.TrimLeft(line, " ") switch { case len(line) == 0: // Keep paragraphs delPrevChar() buffer.WriteString("\n\n") case strings.HasPrefix(leading, "TODO"): // Ignore one line TODOs case strings.HasPrefix(leading, "+"): // Ignore instructions to go2idl default: if strings.HasPrefix(line, " ") || strings.HasPrefix(line, "\t") { delPrevChar() line = "\n" + line + "\n" // Replace it with newline. This is useful when we have a line with: "Example:\n\tJSON-someting..." } else { line += " " } buffer.WriteString(line) } } postDoc := strings.TrimRight(buffer.String(), "\n") postDoc = strings.ReplaceAll(postDoc, "\\\"", "\"") // replace user's \" to " postDoc = strings.ReplaceAll(postDoc, "\"", "\\\"") // Escape " postDoc = strings.ReplaceAll(postDoc, "\n", "\\n") postDoc = strings.ReplaceAll(postDoc, "\t", "\\t") postDoc = strings.ReplaceAll(postDoc, "|", "\\|") return postDoc } func toLink(typeName string) string { selfLink, hasSelfLink := selfLinks[typeName] if hasSelfLink { return wrapInLink(typeName, selfLink) } link, hasLink := links[typeName] if hasLink { return wrapInLink(typeName, link) } return typeName } func wrapInLink(text, link string) string { return fmt.Sprintf("[%s](%s)", text, link) } // fieldName returns the name of the field as it should appear in JSON format // "-" indicates that this field is not part of the JSON representation func fieldName(field *ast.Field) string { jsonTag := "" if field.Tag != nil { jsonTag = reflect.StructTag(field.Tag.Value[1 : len(field.Tag.Value)-1]).Get("json") // Delete first and last quotation if strings.Contains(jsonTag, "inline") { return "-" } } jsonTag = strings.Split(jsonTag, ",")[0] // This can return "-" if jsonTag == "" { if field.Names != nil { return field.Names[0].Name } return field.Type.(*ast.Ident).Name } return jsonTag } // fieldRequired returns whether a field is a required field. func fieldRequired(field *ast.Field) bool { jsonTag := "" if field.Tag != nil { jsonTag = reflect.StructTag(field.Tag.Value[1 : len(field.Tag.Value)-1]).Get("json") // Delete first and last quotation return !strings.Contains(jsonTag, "omitempty") } return false } func fieldType(typ ast.Expr) string { switch e := typ.(type) { case *ast.Ident: return toLink(e.Name) case *ast.StarExpr: return toLink(fieldType(e.X)) case *ast.SelectorExpr: pkg := e.X.(*ast.Ident) //nolint:errcheck t := e.Sel return toLink(pkg.Name + "." + t.Name) case *ast.ArrayType: return "[]" + toLink(fieldType(e.Elt)) case *ast.MapType: return "map[" + toLink(fieldType(e.Key)) + "]" + toLink(fieldType(e.Value)) default: return "" } } ================================================ FILE: cmd/local-dev/clean.go ================================================ // // Copyright 2023 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. package main import ( "bytes" "context" "fmt" "log" "os/exec" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/client" "github.com/spf13/cobra" "github.com/spf13/viper" ) func addCleanFlags(cmd *cobra.Command) { cmd.Flags().String("cluster-name", "policy-controller-demo", "name of the dev policy controller cluster") } func init() { addCleanFlags(cleanCmd) rootCmd.AddCommand(cleanCmd) } var cleanCmd = &cobra.Command{ Use: "clean", Short: "cleanup the local k8s cluster", Long: "Cleanup the local k8s cluster", PreRunE: func(cmd *cobra.Command, _ []string) error { if err := viper.BindPFlags(cmd.Flags()); err != nil { log.Fatal("Error initializing cmd line args: ", err) } return nil }, Run: func(_ *cobra.Command, _ []string) { clean() }, } func clean() { var stderr bytes.Buffer // clean up the local cluster clusterName := viper.GetString("cluster-name") fmt.Printf("Cleaning up the kind cluster %s...\n", clusterName) removeCluster := exec.Command("kind", "delete", "cluster", "--name", clusterName) removeCluster.Stderr = &stderr if err := removeCluster.Run(); err != nil { log.Fatal(buildFatalMessage(err, stderr)) } if err := cleanUpRegistry(); err != nil { log.Fatal(err) } } func cleanUpRegistry() error { ctx := context.Background() dockerCLI, err := client.NewClientWithOpts( client.FromEnv, client.WithAPIVersionNegotiation(), ) if err != nil { return err } defer dockerCLI.Close() containers, err := dockerCLI.ContainerList(ctx, container.ListOptions{Filters: filters.NewArgs(filters.KeyValuePair{Key: "name", Value: "registry.local"})}) if err != nil { return err } if len(containers) > 0 { fmt.Println("Cleaning up registry.local...") if err := dockerCLI.ContainerStop(ctx, containers[0].ID, container.StopOptions{}); err != nil { return err } if err := dockerCLI.ContainerRemove(ctx, containers[0].ID, container.RemoveOptions{}); err != nil { return err } } return nil } ================================================ FILE: cmd/local-dev/main.go ================================================ // // Copyright 2023 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. package main func main() { Execute() } ================================================ FILE: cmd/local-dev/root.go ================================================ // // Copyright 2023 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. package main import ( "fmt" "os" "github.com/spf13/cobra" ) var rootCmd = &cobra.Command{ Use: "local-dev", Short: "Create, manage, and destroy a local k8s cluster for testing the policy controller", Long: "Create, manage, and destroy a local k8s cluster for testing the policy controller", } func Execute() { if err := rootCmd.Execute(); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } ================================================ FILE: cmd/local-dev/setup.go ================================================ // // Copyright 2023 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. package main import ( "bytes" "context" "fmt" "io/fs" "log" "os" "os/exec" "path/filepath" "regexp" "strconv" "github.com/docker/docker/api/types/container" "github.com/docker/docker/client" "github.com/docker/go-connections/nat" "github.com/spf13/cobra" "github.com/spf13/viper" ) const ( localRegistryName = "registry.local" localRegistryPort = 5001 defaultKindestNodeVersionTag = "v1.27.3" ) var kindClusterConfig = ` apiVersion: kind.x-k8s.io/v1alpha4 kind: Cluster name: "%s" nodes: - role: control-plane image: "%s" # Configure registry for KinD. containerdConfigPatches: - |- [plugins."io.containerd.grpc.v1.cri".registry.mirrors."%s:%d"] endpoint = ["http://%s:%d"] ` // check that a supplied image version is in the expected semver format: v.. var semverRegexp = regexp.MustCompile("^v[0-9]+.[0-9]+.[0-9]+$") // check that registry URLs are in the expected format : var registryURLRegexp = regexp.MustCompile("^[a-zA-Z0-9]+.[a-z]+:[0-9]+$") func addSetupFlags(cmd *cobra.Command) { cmd.Flags().String("cluster-name", "policy-controller-demo", "name of the dev policy controller cluster") cmd.Flags().String("k8s-version", defaultKindestNodeVersionTag, "name of the Ko Docker repository to use") cmd.Flags().String("registry-url", "registry.local", "URL and port of the Ko Docker registry to use. Expected format: :. If no registry is provided, the local Kind registry will be used") } var setupCmd = &cobra.Command{ Use: "setup", Short: "setup local k8s cluster for testing policy controller", Long: "Setup a local k8s cluster for testing policy controller", PreRunE: func(cmd *cobra.Command, _ []string) error { if err := viper.BindPFlags(cmd.Flags()); err != nil { log.Fatal("Error initializing cmd line args: ", err) } return nil }, Run: func(_ *cobra.Command, _ []string) { setup() }, } func buildFatalMessage(err error, stderr bytes.Buffer) string { return fmt.Sprintf("%v: %s", err, stderr.String()) } func setup() { var stderr bytes.Buffer registryURL := viper.GetString("registry-url") if registryURL == localRegistryName { fullLocalRegistryURL := fmt.Sprintf("%s:%d/sigstore", localRegistryName, localRegistryPort) err := os.Setenv("KO_DOCKER_REPO", fullLocalRegistryURL) if err != nil { log.Fatal(buildFatalMessage(err, stderr)) } } else { if !registryURLRegexp.Match([]byte(registryURL)) { log.Fatal(fmt.Errorf("provided registry URL is not in the expected format: :")) } err := os.Setenv("KO_DOCKER_REPO", registryURL) if err != nil { log.Fatal(buildFatalMessage(err, stderr)) } } // Create the new Kind cluster clusterName := viper.GetString("cluster-name") fmt.Printf("Creating Kind cluster %s...\n", clusterName) clusterConfig, err := createKindConfig(clusterName, viper.GetString("k8s-version")) if err != nil { log.Fatal(err) } configBytes := []byte(clusterConfig) err = os.WriteFile("kind.yaml", configBytes, 0600) if err != nil { log.Fatal(err) } startKindCluster := exec.Command("kind", "create", "cluster", "--config", "kind.yaml") startKindCluster.Stderr = &stderr if err := startKindCluster.Run(); err != nil { log.Fatal(buildFatalMessage(err, stderr)) } if registryURL == localRegistryName { if err = setupLocalRegistry(); err != nil { log.Fatal(err) } } setGitHash := exec.Command("git", "rev-parse", "HEAD") setGitHash.Stderr = &stderr outBytes, err := setGitHash.Output() if err != nil { log.Fatal(buildFatalMessage(err, stderr)) } err = os.Setenv("GIT_HASH", string(outBytes)) if err != nil { log.Fatal(buildFatalMessage(err, stderr)) } setGitVersion := exec.Command("git", "describe", "--tags", "--always", "--dirty") setGitVersion.Stderr = &stderr outBytes, err = setGitVersion.Output() if err != nil { log.Fatal(buildFatalMessage(err, stderr)) } err = os.Setenv("GIT_VERSION", string(outBytes)) if err != nil { log.Fatal(buildFatalMessage(err, stderr)) } var configFiles []string err = filepath.WalkDir("config", func(path string, d fs.DirEntry, err error) error { if err != nil { return err } if filepath.Ext(d.Name()) == ".yaml" && d.Name() != "kustomization.yaml" { configFiles = append(configFiles, path) } return nil }) if err != nil { log.Fatal(err) } fmt.Println("Applying local policy controller manifests...") for _, configFile := range configFiles { koApply := exec.Command("ko", "apply", "-f", configFile) koApply.Stderr = &stderr _, err = koApply.Output() if err != nil { log.Fatal(buildFatalMessage(err, stderr)) } } } func createKindConfig(clusterName, k8sVersion string) (string, error) { // check that the provided version is in the expected format and use it if !semverRegexp.Match([]byte(k8sVersion)) { return "", fmt.Errorf("provided k8s version %s is not in the expected semver format v..", k8sVersion) } kindImage := fmt.Sprintf("kindest/node:%s", k8sVersion) return fmt.Sprintf(kindClusterConfig, clusterName, kindImage, localRegistryName, localRegistryPort, localRegistryName, localRegistryPort), nil } func setupLocalRegistry() error { dockerCLI, err := client.NewClientWithOpts( client.FromEnv, client.WithAPIVersionNegotiation(), ) if err != nil { return nil } defer dockerCLI.Close() fmt.Printf("\nStarting local registry %s...\n", localRegistryName) ctx := context.Background() resp, err := dockerCLI.ContainerCreate(ctx, &container.Config{ Image: "registry:2", Env: []string{fmt.Sprintf("REGISTRY_HTTP_ADDR=0.0.0.0:%d", localRegistryPort)}, ExposedPorts: nat.PortSet{"5001/tcp": struct{}{}}, }, &container.HostConfig{ RestartPolicy: container.RestartPolicy{Name: "always"}, PortBindings: nat.PortMap{ "5001/tcp": []nat.PortBinding{ {HostIP: "127.0.0.1", HostPort: strconv.Itoa(localRegistryPort)}, }, }, }, nil, nil, localRegistryName) if err != nil { return err } if err := dockerCLI.ContainerStart(ctx, resp.ID, container.StartOptions{}); err != nil { return err } fmt.Println("Connecting network between kind with local registry ...") return dockerCLI.NetworkConnect(ctx, "kind", localRegistryName, nil) } func init() { addSetupFlags(setupCmd) rootCmd.AddCommand(setupCmd) } ================================================ FILE: cmd/sample/main.go ================================================ // // Copyright 2021 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. package main import "log" func main() { log.Printf("Hello, World!") } ================================================ FILE: cmd/schema/main.go ================================================ // 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. package main import ( "log" "knative.dev/hack/schema/commands" "knative.dev/hack/schema/registry" v1alpha1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" v1beta1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1beta1" ) // schema is a tool to dump the schema for policy-controller resources. func main() { registry.Register(&v1alpha1.ClusterImagePolicy{}) registry.Register(&v1alpha1.TrustRoot{}) registry.Register(&v1beta1.ClusterImagePolicy{}) if err := commands.New("github.com/sigstore/policy-controller").Execute(); err != nil { log.Fatal("Error during command execution: ", err) } } ================================================ FILE: cmd/tester/main.go ================================================ // // 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. package main import ( "context" "encoding/json" "flag" "fmt" "log" "os" "strings" "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/name" "go.uber.org/zap" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "knative.dev/pkg/apis" "knative.dev/pkg/logging" "sigs.k8s.io/release-utils/version" "sigs.k8s.io/yaml" "github.com/sigstore/policy-controller/pkg/apis/config" "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" policycontrollerconfig "github.com/sigstore/policy-controller/pkg/config" "github.com/sigstore/policy-controller/pkg/policy" "github.com/sigstore/policy-controller/pkg/webhook" ) type output struct { Errors []string `json:"errors,omitempty"` Warnings []string `json:"warnings,omitempty"` } type LogLevel string const ( LevelDebug LogLevel = "debug" LevelInfo LogLevel = "info" LevelWarn LogLevel = "warn" LevelError LogLevel = "error" ) func getSugaredLogger(value string) (*zap.SugaredLogger, error) { ll := LogLevel(value) switch ll { case LevelDebug, LevelInfo, LevelWarn, LevelError: return setSugaredLogger(ll) default: return nil, fmt.Errorf("invalid log level") } } func setSugaredLogger(logLevel LogLevel) (*zap.SugaredLogger, error) { cfg := zap.NewDevelopmentConfig() switch logLevel { case LevelDebug: cfg.Level.SetLevel(zap.DebugLevel) case LevelInfo: cfg.Level.SetLevel(zap.InfoLevel) case LevelWarn: cfg = zap.NewProductionConfig() cfg.Level.SetLevel(zap.WarnLevel) case LevelError: cfg = zap.NewProductionConfig() cfg.Level.SetLevel(zap.ErrorLevel) default: panic("invalid log level") } logger, err := cfg.Build() if err != nil { return nil, fmt.Errorf("failed to build logger: %w", err) } return logger.Sugar(), nil } func main() { cipFilePath := flag.String("policy", "", "path to ClusterImagePolicy or URL to fetch from (http/https)") versionFlag := flag.Bool("version", false, "return the policy-controller tester version") image := flag.String("image", "", "image to compare against policy") resourceFilePath := flag.String("resource", "", "path to a kubernetes resource to use with includeSpec, includeObjectMeta") trustRootFilePath := flag.String("trustroot", "", "path to a kubernetes TrustRoot resource to use with the ClusterImagePolicy") logLevelStr := flag.String("log-level", "info", "configure the tool's log level (debug, info, warn, error)") enableOCI11 := flag.Bool("enable-oci11", false, "enable experimental OCI 1.1 referrers API for attestation discovery") flag.Parse() logger, err := getSugaredLogger(*logLevelStr) if err != nil { flag.Usage() os.Exit(1) } ctx := logging.WithLogger(context.Background(), logger) // Set up policy controller configuration with OCI 1.1 support if *enableOCI11 { policyConfig := &policycontrollerconfig.PolicyControllerConfig{ NoMatchPolicy: "deny", FailOnEmptyAuthorities: true, EnableOCI11: true, } ctx = policycontrollerconfig.ToContext(ctx, policyConfig) } if *versionFlag { v := version.GetVersionInfo() fmt.Println(v.String()) os.Exit(0) } if *cipFilePath == "" || *image == "" { flag.Usage() os.Exit(1) } pols := make([]policy.Source, 0, 1) if strings.HasPrefix(*cipFilePath, "https://") || strings.HasPrefix(*cipFilePath, "http://") { pols = append(pols, policy.Source{ URL: *cipFilePath, }) } else { pols = append(pols, policy.Source{ Path: *cipFilePath, }) } logging.FromContext(ctx).Infof("Validating policy\n") v := policy.Verification{ NoMatchPolicy: "deny", Policies: &pols, } if err := v.Validate(ctx); err != nil { // CIP validation can return Warnings so let's just go through them // and only exit if there are Errors. if warnFE := err.Filter(apis.WarningLevel); warnFE != nil { log.Printf("CIP has warnings:\n%s\n", warnFE.Error()) } if errorFE := err.Filter(apis.ErrorLevel); errorFE != nil { log.Fatalf("CIP is invalid: %s", errorFE.Error()) } } logging.FromContext(ctx).Infof("Policy was successfully validated\n") ref, err := name.ParseReference(*image) if err != nil { log.Fatal(err) } warningStrings := []string{} vfy, err := policy.Compile(ctx, v, func(s string, i ...interface{}) { warningStrings = append(warningStrings, fmt.Sprintf(s, i...)) }) if err != nil { log.Fatal(err) } if *resourceFilePath != "" { logging.FromContext(ctx).Infof("Parsing the provided Kubernetes resource\n") raw, err := os.ReadFile(*resourceFilePath) if err != nil { log.Fatal(err) } uo := &unstructured.Unstructured{} if err := yaml.Unmarshal(raw, uo); err != nil { log.Fatal(err) } m, ok := uo.Object["metadata"] if !ok { log.Fatal("kubernetes resource is missing metadata key") } ctx = webhook.IncludeObjectMeta(ctx, m) spec, ok := uo.Object["spec"] if !ok { log.Fatal("kubernetes resource is missing spec key") } ctx = webhook.IncludeSpec(ctx, spec) kind, ok := uo.Object["kind"] if !ok { log.Fatal("kubernetes resource is missing kind key") } apiVersion, ok := uo.Object["apiVersion"] if !ok { log.Fatal("kubernetes resource is missing apiVersion key") } typeMeta := make(map[string]interface{}) typeMeta["kind"] = kind typeMeta["apiVersion"] = apiVersion ctx = webhook.IncludeTypeMeta(ctx, typeMeta) logging.FromContext(ctx).Infof("The Kuberentes resource will be used with includeSpec\n") } if *trustRootFilePath != "" { logging.FromContext(ctx).Infof("Parsing the custom trust root\n") configCtx := config.FromContextOrDefaults(ctx) raw, err := os.ReadFile(*trustRootFilePath) if err != nil { log.Fatal(err) } tr := &v1alpha1.TrustRoot{} if err := yaml.Unmarshal(raw, tr); err != nil { log.Fatal(err) } keys, err := GetKeysFromTrustRoot(ctx, tr) if err != nil { log.Fatal(err) } maps := make(map[string]*config.SigstoreKeys, 0) maps[tr.Name] = keys configCtx.SigstoreKeysConfig = &config.SigstoreKeysMap{SigstoreKeys: maps} ctx = config.ToContext(ctx, configCtx) logging.FromContext(ctx).Infof("The custom trust root has been successfully added\n") } logging.FromContext(ctx).Infof("Verifying the provided image against the policy\n") errStrings := []string{} if err := vfy.Verify(ctx, ref, authn.DefaultKeychain); err != nil { errStrings = append(errStrings, strings.Trim(err.Error(), "\n")) } if len(errStrings) != 0 { logging.FromContext(ctx).Infof("Errors encountered during verification\n") var o []byte o, err = json.Marshal(&output{ Errors: errStrings, Warnings: warningStrings, }) if err != nil { log.Fatal(err) } fmt.Println(string(o)) os.Exit(1) } logging.FromContext(ctx).Infof("Verification was successful!\n") } ================================================ FILE: cmd/tester/trustroot.go ================================================ // // 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. package main import ( "context" "fmt" "github.com/sigstore/policy-controller/pkg/apis/config" "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" "github.com/sigstore/policy-controller/pkg/reconciler/trustroot" "github.com/sigstore/policy-controller/pkg/tuf" ) func GetKeysFromTrustRoot(ctx context.Context, tr *v1alpha1.TrustRoot) (*config.SigstoreKeys, error) { switch { case tr.Spec.Remote != nil: mirror := tr.Spec.Remote.Mirror.String() client, err := tuf.ClientFromRemote(context.Background(), mirror, tr.Spec.Remote.Root, tr.Spec.Remote.Targets) if err != nil { return nil, fmt.Errorf("failed to initialize TUF client from remote: %w", err) } return trustroot.GetSigstoreKeysFromTuf(ctx, client, "") case tr.Spec.Repository != nil: client, err := tuf.ClientFromSerializedMirror(context.Background(), tr.Spec.Repository.MirrorFS, tr.Spec.Repository.Root, tr.Spec.Repository.Targets, v1alpha1.DefaultTUFRepoPrefix) if err != nil { return nil, fmt.Errorf("failed to initialize TUF client from remote: %w", err) } return trustroot.GetSigstoreKeysFromTuf(ctx, client, "") case tr.Spec.SigstoreKeys != nil: return config.ConvertSigstoreKeys(context.Background(), tr.Spec.SigstoreKeys) } return nil, fmt.Errorf("provided trust root configuration is not supported") } ================================================ FILE: cmd/webhook/depcheck_test.go ================================================ // // Copyright 2021 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. package main_test import ( "testing" "knative.dev/pkg/depcheck" ) func TestNoDeps(t *testing.T) { depcheck.AssertNoDependency(t, map[string][]string{ "github.com/sigstore/policy-controller/cmd/webhook": { // This conflicts with klog, we error on startup about // `-log_dir` being defined multiple times. // Note: this dependency has been replaced with a version // that does not cause the error // "github.com/golang/glog", }, }) } ================================================ FILE: cmd/webhook/main.go ================================================ // // Copyright 2021 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. package main import ( "context" "flag" "fmt" "log" "os" "time" policyduckv1beta1 "github.com/sigstore/policy-controller/pkg/apis/duck/v1beta1" "github.com/sigstore/policy-controller/pkg/apis/policy" "github.com/sigstore/policy-controller/pkg/apis/policy/common" "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" "github.com/sigstore/policy-controller/pkg/apis/policy/v1beta1" policycontrollerconfig "github.com/sigstore/policy-controller/pkg/config" "github.com/sigstore/policy-controller/pkg/reconciler/clusterimagepolicy" "github.com/sigstore/policy-controller/pkg/reconciler/trustroot" admissionregistrationv1 "k8s.io/api/admissionregistration/v1" appsv1 "k8s.io/api/apps/v1" batchv1 "k8s.io/api/batch/v1" batchv1beta1 "k8s.io/api/batch/v1beta1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/sets" duckv1 "knative.dev/pkg/apis/duck/v1" kubeclient "knative.dev/pkg/client/injection/kube/client" "knative.dev/pkg/configmap" "knative.dev/pkg/controller" "knative.dev/pkg/injection/sharedmain" "knative.dev/pkg/logging" "knative.dev/pkg/signals" "knative.dev/pkg/webhook" "knative.dev/pkg/webhook/certificates" "knative.dev/pkg/webhook/resourcesemantics" "knative.dev/pkg/webhook/resourcesemantics/conversion" "knative.dev/pkg/webhook/resourcesemantics/defaulting" "knative.dev/pkg/webhook/resourcesemantics/validation" "sigs.k8s.io/release-utils/version" "github.com/sigstore/sigstore/pkg/tuf" "github.com/sigstore/policy-controller/pkg/apis/config" pctuf "github.com/sigstore/policy-controller/pkg/tuf" cwebhook "github.com/sigstore/policy-controller/pkg/webhook" ) var ( // webhookName holds the name of the validating and mutating webhook // configuration resources dispatching admission requests to policy-controller. // It is also the name of the webhook which is injected by the controller // with the resource types, namespace selectors, CABundle and service path. // If this changes, you must also change: // // ./config/500-webhook-configuration.yaml // https://github.com/sigstore/helm-charts/blob/main/charts/policy-controller/templates/webhook/webhook_mutating.yaml // https://github.com/sigstore/helm-charts/blob/main/charts/policy-controller/templates/webhook/webhook_validating.yaml webhookName = flag.String("webhook-name", "policy.sigstore.dev", "The name of the validating and mutating webhook configurations as well as the webhook name that is automatically configured, if exists, with different rules and client settings setting how the admission requests to be dispatched to policy-controller.") tufMirror = flag.String("tuf-mirror", tuf.DefaultRemoteRoot, "Alternate TUF mirror. If left blank, public sigstore one is used") tufRoot = flag.String("tuf-root", "", "Alternate TUF root.json. If left blank, public sigstore one is used") // Do not initialize TUF at all. // https://github.com/sigstore/policy-controller/issues/354 disableTUF = flag.Bool("disable-tuf", false, "Disable TUF support.") // 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 // with the resource types, namespace selectors, CABindle and service path. // If this changes, you must also change: // ./config/501-policy-webhook-configurations.yaml // https://github.com/sigstore/helm-charts/blob/main/charts/policy-controller/templates/policy-webhook/policy_webhook_configurations.yaml mutatingCIPWebhookName = flag.String("mutating-webhook-name", "defaulting.clusterimagepolicy.sigstore.dev", "The name of the mutating webhook configuration as well as the webhook name that is automatically configured, if exists, with different rules and client settings setting how the admission requests to be dispatched to policy-webhook.") // validatingCIPWebhookName holds the name of the validating webhook configuration // resource dispatching admission requests to policy-webhook. // It is also the name of the webhook which is injected by the controller // with the resource types, namespace selectors, CABindle and service path. // If this changes, you must also change: // ./config/501-policy-webhook-configurations.yaml // https://github.com/sigstore/helm-charts/blob/main/charts/policy-controller/templates/policy-webhook/policy_webhook_configurations.yaml validatingCIPWebhookName = flag.String("validating-webhook-name", "validating.clusterimagepolicy.sigstore.dev", "The name of the validating webhook configuration as well as the webhook name that is automatically configured, if exists, with different rules and client settings setting how the admission requests to be dispatched to policy-webhook.") // policyResyncPeriod holds the interval which ClusterImagePolicies will resync // This is essential for triggering a reconcile update for potentially stale KMS authorities. policyResyncPeriod = flag.Duration("policy-resync-period", 10*time.Hour, "The resync period for ClusterImagePolicies. The default is 10h.") // trustrootResyncPeriod holds the interval which the TrustRoot will resync // This is essential for triggering a reconcile update for potentially stale TUF metadata. trustrootResyncPeriod = flag.Duration("trustroot-resync-period", 24*time.Hour, "The resync period for ClusterImagePolicies. The default is 24h.") ) func main() { opts := webhook.Options{ ServiceName: "webhook", Port: 8443, SecretName: "webhook-certs", } ctx := webhook.WithOptions(signals.NewContext(), opts) // Allow folks to configure the port the webhook serves on. flag.IntVar(&opts.Port, "secure-port", opts.Port, "The port on which to serve HTTPS.") flag.Parse() // If TUF has been disabled do not try to set it up. if !*disableTUF { // If they provided an alternate TUF root file to use, read it here. var tufRootBytes []byte var err error if *tufRoot != "" { tufRootBytes, err = os.ReadFile(*tufRoot) if err != nil { logging.FromContext(ctx).Panicf("Failed to read alternate TUF root file %s : %v", *tufRoot, err) } } logging.FromContext(ctx).Infof("Initializing TUF root from %s => %s", *tufRoot, *tufMirror) if err := tuf.Initialize(ctx, *tufMirror, tufRootBytes); err != nil { logging.FromContext(ctx).Panicf("Failed to initialize TUF client from %s : %v", *tufRoot, err) } } // Set the policy and trust root resync periods ctx = clusterimagepolicy.ToContext(ctx, *policyResyncPeriod) ctx = pctuf.ToContext(ctx, *trustrootResyncPeriod) // 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") v := version.GetVersionInfo() vJSON, _ := v.JSONString() log.Printf("%v", vJSON) // This calls flag.Parse() sharedmain.MainWithContext(ctx, "policy-controller", certificates.NewController, NewValidatingAdmissionController, NewMutatingAdmissionController, trustroot.NewController, clusterimagepolicy.NewController, NewPolicyValidatingAdmissionController, NewPolicyMutatingAdmissionController, newConversionController, ) } var ( _ resourcesemantics.SubResourceLimited = (*crdNoStatusUpdatesOrDeletes)(nil) _ resourcesemantics.VerbLimited = (*crdNoStatusUpdatesOrDeletes)(nil) _ resourcesemantics.SubResourceLimited = (*crdEphemeralContainers)(nil) _ resourcesemantics.VerbLimited = (*crdEphemeralContainers)(nil) ) type crdNoStatusUpdatesOrDeletes struct { resourcesemantics.GenericCRD } type crdEphemeralContainers struct { resourcesemantics.GenericCRD } func (c *crdNoStatusUpdatesOrDeletes) SupportedSubResources() []string { // We do not want any updates that are for status, scale, or anything else. return []string{""} } func (c *crdEphemeralContainers) SupportedSubResources() []string { return []string{"/ephemeralcontainers", ""} } func (c *crdNoStatusUpdatesOrDeletes) SupportedVerbs() []admissionregistrationv1.OperationType { return []admissionregistrationv1.OperationType{ admissionregistrationv1.Create, admissionregistrationv1.Update, } } func (c *crdEphemeralContainers) SupportedVerbs() []admissionregistrationv1.OperationType { return []admissionregistrationv1.OperationType{ admissionregistrationv1.Create, admissionregistrationv1.Update, } } 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{}}, } var typesCIP = map[schema.GroupVersionKind]resourcesemantics.GenericCRD{ // v1alpha1 v1alpha1.SchemeGroupVersion.WithKind("ClusterImagePolicy"): &v1alpha1.ClusterImagePolicy{}, v1alpha1.SchemeGroupVersion.WithKind("TrustRoot"): &v1alpha1.TrustRoot{}, // v1beta1 v1beta1.SchemeGroupVersion.WithKind("ClusterImagePolicy"): &v1beta1.ClusterImagePolicy{}, } func NewValidatingAdmissionController(ctx context.Context, cmw configmap.Watcher) *controller.Impl { // Decorate contexts with the current state of the config. store := config.NewStore(logging.FromContext(ctx).Named("config-store")) store.WatchConfigs(cmw) policyControllerConfigStore := policycontrollerconfig.NewStore(logging.FromContext(ctx).Named("config-policy-controller")) policyControllerConfigStore.WatchConfigs(cmw) logger := logging.FromContext(ctx) woptions := webhook.GetOptions(ctx) woptions.ControllerOptions = &controller.ControllerOptions{ WorkQueueName: fmt.Sprintf("%s-%s", *webhookName, "validating"), Logger: logger.Named(*webhookName), } ctx = webhook.WithOptions(ctx, *woptions) kc := kubeclient.Get(ctx) validator := cwebhook.NewValidator(ctx) return validation.NewAdmissionController(ctx, // Name of the resource webhook. *webhookName, // The path on which to serve the webhook. "/validations", // The resources to validate. types, // A function that infuses the context passed to Validate/SetDefaults with custom metadata. func(ctx context.Context) context.Context { ctx = context.WithValue(ctx, kubeclient.Key{}, kc) ctx = store.ToContext(ctx) ctx = policyControllerConfigStore.ToContext(ctx) ctx = policyduckv1beta1.WithPodScalableValidator(ctx, validator.ValidatePodScalable) ctx = duckv1.WithPodValidator(ctx, validator.ValidatePod) ctx = duckv1.WithPodSpecValidator(ctx, validator.ValidatePodSpecable) ctx = duckv1.WithCronJobValidator(ctx, validator.ValidateCronJob) return ctx }, // Whether to disallow unknown fields. // We pass false because we're using partial schemas. false, // Extra validating callbacks to be applied to resources. nil, ) } func NewMutatingAdmissionController(ctx context.Context, _ configmap.Watcher) *controller.Impl { kc := kubeclient.Get(ctx) logger := logging.FromContext(ctx) woptions := webhook.GetOptions(ctx) woptions.ControllerOptions = &controller.ControllerOptions{ WorkQueueName: fmt.Sprintf("%s-%s", *webhookName, "mutating"), Logger: logger.Named(*webhookName), } ctx = webhook.WithOptions(ctx, *woptions) validator := cwebhook.NewValidator(ctx) return defaulting.NewAdmissionController(ctx, // Name of the resource webhook. *webhookName, // The path on which to serve the webhook. "/mutations", // The resources to validate. types, // A function that infuses the context passed to Validate/SetDefaults with custom metadata. func(ctx context.Context) context.Context { ctx = context.WithValue(ctx, kubeclient.Key{}, kc) ctx = policyduckv1beta1.WithPodScalableDefaulter(ctx, validator.ResolvePodScalable) ctx = duckv1.WithPodDefaulter(ctx, validator.ResolvePod) ctx = duckv1.WithPodSpecDefaulter(ctx, validator.ResolvePodSpecable) ctx = duckv1.WithCronJobDefaulter(ctx, validator.ResolveCronJob) return ctx }, // Whether to disallow unknown fields. // We pass false because we're using partial schemas. false, ) } func NewPolicyValidatingAdmissionController(ctx context.Context, cmw configmap.Watcher) *controller.Impl { store := config.NewStore(logging.FromContext(ctx).Named("config-store")) store.WatchConfigs(cmw) policyControllerConfigStore := policycontrollerconfig.NewStore(logging.FromContext(ctx).Named("config-policy-controller")) policyControllerConfigStore.WatchConfigs(cmw) logger := logging.FromContext(ctx) woptions := webhook.GetOptions(ctx) woptions.ControllerOptions = &controller.ControllerOptions{ WorkQueueName: *validatingCIPWebhookName, Logger: logger.Named(*validatingCIPWebhookName), } ctx = webhook.WithOptions(ctx, *woptions) return validation.NewAdmissionController( ctx, *validatingCIPWebhookName, "/validating", typesCIP, func(ctx context.Context) context.Context { ctx = policyControllerConfigStore.ToContext(ctx) return ctx }, true, ) } func NewPolicyMutatingAdmissionController(ctx context.Context, _ configmap.Watcher) *controller.Impl { woptions := webhook.GetOptions(ctx) logger := logging.FromContext(ctx) woptions.ControllerOptions = &controller.ControllerOptions{ WorkQueueName: *mutatingCIPWebhookName, Logger: logger.Named(*mutatingCIPWebhookName), } ctx = webhook.WithOptions(ctx, *woptions) return defaulting.NewAdmissionController( ctx, *mutatingCIPWebhookName, "/defaulting", typesCIP, func(ctx context.Context) context.Context { return ctx }, true, ) } func newConversionController(ctx context.Context, _ configmap.Watcher) *controller.Impl { // nolint: revive var ( v1alpha1GroupVersion = v1alpha1.SchemeGroupVersion.Version v1beta1GroupVersion = v1beta1.SchemeGroupVersion.Version ) logger := logging.FromContext(ctx) woptions := webhook.GetOptions(ctx) woptions.ControllerOptions = &controller.ControllerOptions{ WorkQueueName: "resource-conversion", Logger: logger.Named("resource-conversion"), } ctx = webhook.WithOptions(ctx, *woptions) return conversion.NewConversionController(ctx, // The path on which to serve the webhook "/resource-conversion", // Specify the types of custom resource definitions that should be converted map[schema.GroupKind]conversion.GroupKindConversion{ v1beta1.Kind("ClusterImagePolicy"): { DefinitionName: policy.ClusterImagePolicyResource.String(), HubVersion: v1alpha1GroupVersion, Zygotes: map[string]conversion.ConvertibleObject{ v1alpha1GroupVersion: &v1alpha1.ClusterImagePolicy{}, v1beta1GroupVersion: &v1beta1.ClusterImagePolicy{}, }, }, }, // A function that infuses the context passed to ConvertTo/ConvertFrom/SetDefaults with custom metadata func(ctx context.Context) context.Context { return ctx }, ) } ================================================ FILE: config/100-namespace.yaml ================================================ # Copyright 2021 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 # # https://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. apiVersion: v1 kind: Namespace metadata: name: cosign-system labels: policy.sigstore.dev/include: "false" ================================================ FILE: config/200-clusterrole.yaml ================================================ # Copyright 2021 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 # # https://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. kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: policy-controller-rbac rules: - apiGroups: [""] resources: ["events"] verbs: ["create","patch"] - apiGroups: ["admissionregistration.k8s.io"] resources: ["validatingwebhookconfigurations/finalizers", "mutatingwebhookconfigurations/finalizers"] resourceNames: ["policy.sigstore.dev", "validating.clusterimagepolicy.sigstore.dev", "defaulting.clusterimagepolicy.sigstore.dev"] verbs: ["update"] # Allow the reconciliation of exactly our validating and mutating webhooks. - apiGroups: ["admissionregistration.k8s.io"] resources: ["validatingwebhookconfigurations", "mutatingwebhookconfigurations"] verbs: ["list", "watch"] - apiGroups: ["admissionregistration.k8s.io"] resources: ["validatingwebhookconfigurations", "mutatingwebhookconfigurations"] verbs: ["get", "update", "delete"] resourceNames: ["policy.sigstore.dev", "validating.clusterimagepolicy.sigstore.dev", "defaulting.clusterimagepolicy.sigstore.dev"] - apiGroups: [""] resources: ["namespaces"] verbs: ["get"] # The webhook configured the namespace as the OwnerRef on various cluster-scoped resources, # which requires we can Get the system namespace. resourceNames: ["cosign-system"] - apiGroups: [""] resources: ["namespaces/finalizers"] verbs: ["update"] resourceNames: ["cosign-system"] # Allow the reconciliation of exactly our CRDs. # This is needed for us to patch in conversion webhook information. - apiGroups: ["apiextensions.k8s.io"] resources: ["customresourcedefinitions"] verbs: ["list", "watch"] - apiGroups: ["apiextensions.k8s.io"] resources: ["customresourcedefinitions"] verbs: ["get", "update"] resourceNames: ["clusterimagepolicies.policy.sigstore.dev"] - apiGroups: ["apiextensions.k8s.io"] resources: ["customresourcedefinitions"] verbs: ["get", "update"] resourceNames: ["trustroots.policy.sigstore.dev"] # Allow reconciliation of the ClusterImagePolicy and TrustRoot CRDs. - apiGroups: ["policy.sigstore.dev"] resources: ["clusterimagepolicies", "clusterimagepolicies/status"] verbs: ["get", "list", "update", "watch", "patch"] - apiGroups: ["policy.sigstore.dev"] resources: ["trustroots", "trustroots/status"] verbs: ["get", "list", "update", "watch", "patch"] # This is needed by k8schain to support fetching pull secrets attached to pod specs # or their service accounts. If pull secrets aren't used, the "secrets" below can # be safely dropped, but the logic will fetch the service account to check for pull # secrets. - apiGroups: [""] resources: ["serviceaccounts", "secrets"] verbs: ["get"] ================================================ FILE: config/200-role.yaml ================================================ # Copyright 2021 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 # # https://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. kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: policy-controller-namespace-rbac namespace: cosign-system rules: # Needed to watch and load configuration and secret data. - apiGroups: [""] resources: ["configmaps", "secrets"] verbs: ["get", "list", "update", "watch"] # Needed for leader election - apiGroups: ["coordination.k8s.io"] resources: ["leases"] verbs: ["get", "list", "create", "update", "delete", "patch", "watch"] # This is needed to create / patch ConfigMap that is created by the reconciler # to consolidate various CIP configuration into a policy ConfigMap. - apiGroups: [""] resources: ["configmaps"] resourceNames: ["config-image-policies"] verbs: ["get", "list", "create", "update", "patch", "watch"] # This is needed to create / patch ConfigMap that is created by the reconciler # to consolidate various TrustRoot configuration into SigstoreKeys ConfigMap. - apiGroups: [""] resources: ["configmaps"] resourceNames: ["config-sigstore-keys"] verbs: ["get", "list", "create", "update", "patch", "watch"] ================================================ FILE: config/200-serviceaccount.yaml ================================================ # Copyright 2021 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 # # https://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. apiVersion: v1 kind: ServiceAccount metadata: name: webhook namespace: cosign-system ================================================ FILE: config/201-clusterrolebinding.yaml ================================================ # Copyright 2021 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 # # https://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. apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: policy-controller-webhook subjects: - kind: ServiceAccount name: webhook namespace: cosign-system roleRef: kind: ClusterRole name: policy-controller-rbac apiGroup: rbac.authorization.k8s.io ================================================ FILE: config/201-rolebinding.yaml ================================================ # Copyright 2021 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 # # https://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. apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: policy-controller-webhook namespace: cosign-system subjects: - kind: ServiceAccount name: webhook namespace: cosign-system roleRef: kind: Role name: policy-controller-namespace-rbac apiGroup: rbac.authorization.k8s.io ================================================ FILE: config/300-clusterimagepolicy.yaml ================================================ # 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 # # https://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. apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: clusterimagepolicies.policy.sigstore.dev spec: conversion: strategy: Webhook webhook: conversionReviewVersions: ["v1beta1", "v1alpha1"] clientConfig: service: name: webhook namespace: cosign-system group: policy.sigstore.dev names: kind: ClusterImagePolicy plural: clusterimagepolicies singular: clusterimagepolicy categories: - all - sigstore shortNames: - cip scope: Cluster versions: - name: v1alpha1 served: true storage: true subresources: status: {} schema: openAPIV3Schema: type: object properties: spec: description: Spec holds the desired state of the ClusterImagePolicy (from the client). type: object properties: authorities: description: Authorities defines the rules for discovering and validating signatures. type: array items: type: object properties: attestations: description: Attestations is a list of individual attestations for this authority, once the signature for this authority has been verified. type: array items: type: object properties: name: description: Name of the attestation. These can then be referenced at the CIP level policy. type: string policy: description: Policy defines all of the matching signatures, and all of the matching attestations (whose attestations are verified). type: object properties: configMapRef: description: ConfigMapRef defines the reference to a configMap with the policy definition. type: object properties: key: description: Key defines the key to pull from the configmap. type: string name: description: Name is unique within a namespace to reference a configmap resource. type: string namespace: description: Namespace defines the space within which the configmap name must be unique. type: string data: description: Data contains the policy definition. type: string fetchConfigFile: description: 'FetchConfigFile controls whether ConfigFile will be fetched and made available for CIP level policy evaluation. Note that this only gets evaluated (and hence fetched) iff at least one authority matches. The ConfigFile will then be available in this format: https://github.com/opencontainers/image-spec/blob/main/config.md' type: boolean includeObjectMeta: description: IncludeObjectMeta controls whether the ObjectMeta will be included and made available for CIP level policy evalutation. Note that this only gets evaluated iff at least one authority matches. type: boolean includeSpec: description: IncludeSpec controls whether resource `Spec` will be included and made available for CIP level policy evaluation. Note that this only gets evaluated iff at least one authority matches. Also note that because Spec may be of a different shape depending on the resource being evaluatied (see MatchResource for filtering) you might want to configure these to match the policy file to ensure the shape of the Spec is what you expect when evaling the policy. type: boolean includeTypeMeta: description: IncludeTypeMeta controls whether the TypeMeta will be included and made available for CIP level policy evalutation. Note that this only gets evaluated iff at least one authority matches. type: boolean remote: description: Remote defines the url to a policy. type: object properties: sha256sum: description: Sha256sum defines the exact sha256sum computed out of the 'body' of the http response. type: string url: description: URL to the policy data. type: string type: description: Which kind of policy this is, currently only rego or cue are supported. Furthermore, only cue is tested :) type: string predicateType: description: PredicateType defines which predicate type to verify. Matches cosign verify-attestation options. type: string ctlog: description: CTLog sets the configuration to verify the authority against a Rekor instance. type: object properties: trustRootRef: description: Use the Public Key from the referred TrustRoot.TLog type: string url: description: URL sets the url to the rekor instance (by default the public rekor.sigstore.dev) type: string key: description: Key defines the type of key to validate the image. type: object properties: data: description: Data contains the inline public key. type: string hashAlgorithm: description: HashAlgorithm always defaults to sha256 if the algorithm hasn't been explicitly set type: string kms: description: KMS contains the KMS url of the public key Supported formats differ based on the KMS system used. type: string secretRef: description: SecretRef sets a reference to a secret with the key. type: object properties: name: description: name is unique within a namespace to reference a secret resource. type: string namespace: description: namespace defines the space within which the secret name must be unique. type: string keyless: description: Keyless sets the configuration to verify the authority against a Fulcio instance. type: object properties: ca-cert: description: CACert sets a reference to CA certificate type: object properties: data: description: Data contains the inline public key. type: string hashAlgorithm: description: HashAlgorithm always defaults to sha256 if the algorithm hasn't been explicitly set type: string kms: description: KMS contains the KMS url of the public key Supported formats differ based on the KMS system used. type: string secretRef: description: SecretRef sets a reference to a secret with the key. type: object properties: name: description: name is unique within a namespace to reference a secret resource. type: string namespace: description: namespace defines the space within which the secret name must be unique. type: string identities: description: Identities sets a list of identities. type: array items: type: object properties: issuer: description: Issuer defines the issuer for this identity. type: string issuerRegExp: description: IssuerRegExp specifies a regular expression to match the issuer for this identity. type: string subject: description: Subject defines the subject for this identity. type: string subjectRegExp: description: SubjectRegExp specifies a regular expression to match the subject for this identity. type: string insecureIgnoreSCT: description: InsecureIgnoreSCT omits verifying if a certificate contains an embedded SCT type: boolean trustRootRef: description: Use the Certificate Chain from the referred TrustRoot.CertificateAuthorities and TrustRoot.CTLog type: string url: description: URL defines a url to the keyless instance. type: string name: description: Name is the name for this authority. Used by the CIP Policy validator to be able to reference matching signature or attestation verifications. If not specified, the name will be authority- type: string rfc3161timestamp: description: RFC3161Timestamp sets the configuration to verify the signature timestamp against a RFC3161 time-stamping instance. type: object properties: trustRootRef: description: Use the Certificate Chain from the referred TrustRoot.TimeStampAuthorities type: string signatureFormat: description: SignatureFormat specifies the format the authority expects. Supported formats are "legacy" and "bundle". If not specified, the default is "legacy" (cosign's default). type: string source: description: Sources sets the configuration to specify the sources from where to consume the signatures. type: array items: type: object properties: oci: description: OCI defines the registry from where to pull the signature / attestations. type: string signaturePullSecrets: description: SignaturePullSecrets is an optional list of references to secrets in the same namespace as the deploying resource for pulling any of the signatures used by this Source. type: array items: type: object properties: name: description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' type: string tagPrefix: description: TagPrefix is an optional prefix that signature and attestations have. This is the 'tag based discovery' and in the future once references are fully supported that should likely be the preferred way to handle these. type: string static: description: Static specifies that signatures / attestations are not validated but instead a static policy is applied against matching images. type: object properties: action: description: Action defines how to handle a matching policy. type: string message: description: For fail actions, emit an optional custom message type: string images: description: Images defines the patterns of image names that should be subject to this policy. type: array items: type: object properties: glob: description: Glob defines a globbing pattern. type: string match: description: Match allows selecting resources based on their properties. type: array items: type: object properties: group: type: string resource: type: string selector: type: object properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. type: array items: type: object properties: key: description: key is the label key that the selector applies to. type: string operator: description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. type: array items: type: string matchLabels: description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. type: object x-kubernetes-preserve-unknown-fields: true version: type: string mode: description: Mode controls whether a failing policy will be rejected (not admitted), or if errors are converted to Warnings. enforce - Reject (default) warn - allow but warn type: string policy: description: Policy is an optional policy that can be applied against all the successfully validated Authorities. If no authorities pass, this does not even get evaluated, as the Policy is considered failed. type: object properties: configMapRef: description: ConfigMapRef defines the reference to a configMap with the policy definition. type: object properties: key: description: Key defines the key to pull from the configmap. type: string name: description: Name is unique within a namespace to reference a configmap resource. type: string namespace: description: Namespace defines the space within which the configmap name must be unique. type: string data: description: Data contains the policy definition. type: string fetchConfigFile: description: 'FetchConfigFile controls whether ConfigFile will be fetched and made available for CIP level policy evaluation. Note that this only gets evaluated (and hence fetched) iff at least one authority matches. The ConfigFile will then be available in this format: https://github.com/opencontainers/image-spec/blob/main/config.md' type: boolean includeObjectMeta: description: IncludeObjectMeta controls whether the ObjectMeta will be included and made available for CIP level policy evalutation. Note that this only gets evaluated iff at least one authority matches. type: boolean includeSpec: description: IncludeSpec controls whether resource `Spec` will be included and made available for CIP level policy evaluation. Note that this only gets evaluated iff at least one authority matches. Also note that because Spec may be of a different shape depending on the resource being evaluatied (see MatchResource for filtering) you might want to configure these to match the policy file to ensure the shape of the Spec is what you expect when evaling the policy. type: boolean includeTypeMeta: description: IncludeTypeMeta controls whether the TypeMeta will be included and made available for CIP level policy evalutation. Note that this only gets evaluated iff at least one authority matches. type: boolean remote: description: Remote defines the url to a policy. type: object properties: sha256sum: description: Sha256sum defines the exact sha256sum computed out of the 'body' of the http response. type: string url: description: URL to the policy data. type: string type: description: Which kind of policy this is, currently only rego or cue are supported. Furthermore, only cue is tested :) type: string status: description: Status represents the current state of the ClusterImagePolicy. This data may be out of date. type: object properties: annotations: description: Annotations is additional Status fields for the Resource to save some additional State as well as convey more information to the user. This is roughly akin to Annotations on any k8s resource, just the reconciler conveying richer information outwards. type: object x-kubernetes-preserve-unknown-fields: true conditions: description: Conditions the latest available observations of a resource's current state. type: array items: type: object required: - type - status properties: lastTransitionTime: description: LastTransitionTime is the last time the condition transitioned from one status to another. We use VolatileTime in place of metav1.Time to exclude this from creating equality.Semantic differences (all other things held constant). type: string message: description: A human readable message indicating details about the transition. type: string reason: description: The reason for the condition's last transition. type: string severity: description: Severity with which to treat failures of this type of condition. When this is not specified, it defaults to Error. type: string status: description: Status of the condition, one of True, False, Unknown. type: string type: description: Type of condition. type: string observedGeneration: description: ObservedGeneration is the 'Generation' of the Service that was last processed by the controller. type: integer format: int64 - name: v1beta1 served: true storage: false subresources: status: {} schema: openAPIV3Schema: type: object properties: spec: description: Spec holds the desired state of the ClusterImagePolicy (from the client). type: object properties: authorities: description: Authorities defines the rules for discovering and validating signatures. type: array items: type: object properties: attestations: description: Attestations is a list of individual attestations for this authority, once the signature for this authority has been verified. type: array items: type: object properties: name: description: Name of the attestation. These can then be referenced at the CIP level policy. type: string policy: description: Policy defines all of the matching signatures, and all of the matching attestations (whose attestations are verified). type: object properties: configMapRef: description: ConfigMapRef defines the reference to a configMap with the policy definition. type: object properties: key: description: Key defines the key to pull from the configmap. type: string name: description: Name is unique within a namespace to reference a configmap resource. type: string namespace: description: Namespace defines the space within which the configmap name must be unique. type: string data: description: Data contains the policy definition. type: string fetchConfigFile: description: 'FetchConfigFile controls whether ConfigFile will be fetched and made available for CIP level policy evaluation. Note that this only gets evaluated (and hence fetched) iff at least one authority matches. The ConfigFile will then be available in this format: https://github.com/opencontainers/image-spec/blob/main/config.md' type: boolean includeObjectMeta: description: IncludeObjectMeta controls whether the ObjectMeta will be included and made available for CIP level policy evalutation. Note that this only gets evaluated iff at least one authority matches. type: boolean includeSpec: description: IncludeSpec controls whether resource `Spec` will be included and made available for CIP level policy evaluation. Note that this only gets evaluated iff at least one authority matches. Also note that because Spec may be of a different shape depending on the resource being evaluatied (see MatchResource for filtering) you might want to configure these to match the policy file to ensure the shape of the Spec is what you expect when evaling the policy. type: boolean includeTypeMeta: description: IncludeTypeMeta controls whether the TypeMeta will be included and made available for CIP level policy evalutation. Note that this only gets evaluated iff at least one authority matches. type: boolean remote: description: Remote defines the url to a policy. type: object properties: sha256sum: description: Sha256sum defines the exact sha256sum computed out of the 'body' of the http response. type: string url: description: URL to the policy data. type: string type: description: Which kind of policy this is, currently only rego or cue are supported. Furthermore, only cue is tested :) type: string predicateType: description: PredicateType defines which predicate type to verify. Matches cosign verify-attestation options. type: string ctlog: description: CTLog sets the configuration to verify the authority against a Rekor instance. type: object properties: trustRootRef: description: Use the Public Key from the referred TrustRoot.TLog type: string url: description: URL sets the url to the rekor instance (by default the public rekor.sigstore.dev) type: string key: description: Key defines the type of key to validate the image. type: object properties: data: description: Data contains the inline public key. type: string hashAlgorithm: description: HashAlgorithm always defaults to sha256 if the algorithm hasn't been explicitly set type: string kms: description: KMS contains the KMS url of the public key Supported formats differ based on the KMS system used. type: string secretRef: description: SecretRef sets a reference to a secret with the key. type: object properties: name: description: name is unique within a namespace to reference a secret resource. type: string namespace: description: namespace defines the space within which the secret name must be unique. type: string keyless: description: Keyless sets the configuration to verify the authority against a Fulcio instance. type: object properties: ca-cert: description: CACert sets a reference to CA certificate type: object properties: data: description: Data contains the inline public key. type: string hashAlgorithm: description: HashAlgorithm always defaults to sha256 if the algorithm hasn't been explicitly set type: string kms: description: KMS contains the KMS url of the public key Supported formats differ based on the KMS system used. type: string secretRef: description: SecretRef sets a reference to a secret with the key. type: object properties: name: description: name is unique within a namespace to reference a secret resource. type: string namespace: description: namespace defines the space within which the secret name must be unique. type: string identities: description: Identities sets a list of identities. type: array items: type: object properties: issuer: description: Issuer defines the issuer for this identity. type: string issuerRegExp: description: IssuerRegExp specifies a regular expression to match the issuer for this identity. type: string subject: description: Subject defines the subject for this identity. type: string subjectRegExp: description: SubjectRegExp specifies a regular expression to match the subject for this identity. type: string insecureIgnoreSCT: description: InsecureIgnoreSCT omits verifying if a certificate contains an embedded SCT type: boolean trustRootRef: description: Use the Certificate Chain from the referred TrustRoot.CertificateAuthorities and TrustRoot.CTLog type: string url: description: URL defines a url to the keyless instance. type: string name: description: Name is the name for this authority. Used by the CIP Policy validator to be able to reference matching signature or attestation verifications. If not specified, the name will be authority- type: string rfc3161timestamp: description: RFC3161Timestamp sets the configuration to verify the signature timestamp against a RFC3161 time-stamping instance. type: object properties: trustRootRef: description: Use the Certificate Chain from the referred TrustRoot.TimeStampAuthorities type: string signatureFormat: description: SignatureFormat specifies the format the authority expects. Supported formats are "legacy" and "bundle". If not specified, the default is "legacy" (cosign's default). type: string source: description: Sources sets the configuration to specify the sources from where to consume the signatures. type: array items: type: object properties: oci: description: OCI defines the registry from where to pull the signature / attestations. type: string signaturePullSecrets: description: SignaturePullSecrets is an optional list of references to secrets in the same namespace as the deploying resource for pulling any of the signatures used by this Source. type: array items: type: object properties: name: description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' type: string tagPrefix: description: TagPrefix is an optional prefix that signature and attestations have. This is the 'tag based discovery' and in the future once references are fully supported that should likely be the preferred way to handle these. type: string static: description: Static specifies that signatures / attestations are not validated but instead a static policy is applied against matching images. type: object properties: action: description: Action defines how to handle a matching policy. type: string message: description: For fail actions, emit an optional custom message type: string images: description: Images defines the patterns of image names that should be subject to this policy. type: array items: type: object properties: glob: description: Glob defines a globbing pattern. type: string match: description: Match allows selecting resources based on their properties. type: array items: type: object properties: group: type: string resource: type: string selector: type: object properties: matchExpressions: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. type: array items: type: object properties: key: description: key is the label key that the selector applies to. type: string operator: description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. type: array items: type: string matchLabels: description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. type: object x-kubernetes-preserve-unknown-fields: true version: type: string mode: description: Mode controls whether a failing policy will be rejected (not admitted), or if errors are converted to Warnings. enforce - Reject (default) warn - allow but warn type: string policy: description: Policy is an optional policy that can be applied against all the successfully validated Authorities. If no authorities pass, this does not even get evaluated, as the Policy is considered failed. type: object properties: configMapRef: description: ConfigMapRef defines the reference to a configMap with the policy definition. type: object properties: key: description: Key defines the key to pull from the configmap. type: string name: description: Name is unique within a namespace to reference a configmap resource. type: string namespace: description: Namespace defines the space within which the configmap name must be unique. type: string data: description: Data contains the policy definition. type: string fetchConfigFile: description: 'FetchConfigFile controls whether ConfigFile will be fetched and made available for CIP level policy evaluation. Note that this only gets evaluated (and hence fetched) iff at least one authority matches. The ConfigFile will then be available in this format: https://github.com/opencontainers/image-spec/blob/main/config.md' type: boolean includeObjectMeta: description: IncludeObjectMeta controls whether the ObjectMeta will be included and made available for CIP level policy evalutation. Note that this only gets evaluated iff at least one authority matches. type: boolean includeSpec: description: IncludeSpec controls whether resource `Spec` will be included and made available for CIP level policy evaluation. Note that this only gets evaluated iff at least one authority matches. Also note that because Spec may be of a different shape depending on the resource being evaluatied (see MatchResource for filtering) you might want to configure these to match the policy file to ensure the shape of the Spec is what you expect when evaling the policy. type: boolean includeTypeMeta: description: IncludeTypeMeta controls whether the TypeMeta will be included and made available for CIP level policy evalutation. Note that this only gets evaluated iff at least one authority matches. type: boolean remote: description: Remote defines the url to a policy. type: object properties: sha256sum: description: Sha256sum defines the exact sha256sum computed out of the 'body' of the http response. type: string url: description: URL to the policy data. type: string type: description: Which kind of policy this is, currently only rego or cue are supported. Furthermore, only cue is tested :) type: string status: description: Status represents the current state of the ClusterImagePolicy. This data may be out of date. type: object properties: annotations: description: Annotations is additional Status fields for the Resource to save some additional State as well as convey more information to the user. This is roughly akin to Annotations on any k8s resource, just the reconciler conveying richer information outwards. type: object x-kubernetes-preserve-unknown-fields: true conditions: description: Conditions the latest available observations of a resource's current state. type: array items: type: object required: - type - status properties: lastTransitionTime: description: LastTransitionTime is the last time the condition transitioned from one status to another. We use VolatileTime in place of metav1.Time to exclude this from creating equality.Semantic differences (all other things held constant). type: string message: description: A human readable message indicating details about the transition. type: string reason: description: The reason for the condition's last transition. type: string severity: description: Severity with which to treat failures of this type of condition. When this is not specified, it defaults to Error. type: string status: description: Status of the condition, one of True, False, Unknown. type: string type: description: Type of condition. type: string observedGeneration: description: ObservedGeneration is the 'Generation' of the Service that was last processed by the controller. type: integer format: int64 ================================================ FILE: config/300-trustroot.yaml ================================================ # 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 # # https://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. apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: trustroots.policy.sigstore.dev spec: conversion: strategy: None group: policy.sigstore.dev names: kind: TrustRoot plural: trustroots singular: trustroot categories: - all - sigstore scope: Cluster versions: - name: v1alpha1 served: true storage: true subresources: status: {} schema: openAPIV3Schema: type: object properties: spec: description: Spec is the definition for a trust root. This is either a TUF root and remote or local repository. You can also bring your own keys/certs here. type: object properties: remote: description: Remote specifies initial root of trust & remote mirror. type: object properties: mirror: description: 'Mirror is the remote mirror, for example: https://tuf-repo-cdn.sigstore.dev' type: string root: description: Root is the base64 encoded, json trusted initial root. type: string targets: description: Targets is where the targets live off of the root of the Remote If not specified 'targets' is defaulted. type: string trustedRootTarget: description: TrustedRootTarget is the name of the target containing the JSON trusted root. If not specified, `trusted_root.json` is used. type: string repository: description: Repository contains the serialized TUF remote repository. type: object properties: mirrorFS: description: MirrorFS is the base64 tarred, gzipped, and base64 encoded remote repository that can be used for example in air-gap environments. Will not make outbound network connections, and must then be kept up to date in some other manner. The repository must contain metadata as well as targets. type: string root: description: Root is the base64 encoded, json trusted initial root. type: string targets: description: Targets is where the targets live off of the root of the Repository above. If not specified 'targets' is defaulted. type: string trustedRootTarget: description: TrustedRootTarget is the name of the target containing the JSON trusted root. If not specified, `trusted_root.json` is used. type: string sigstoreKeys: description: SigstoreKeys contains the serialized keys. type: object properties: certificateAuthorities: description: Trusted certificate authorities (e.g Fulcio). type: array items: type: object properties: certChain: description: The certificate chain for this CA in PEM format. Last entry in this chain is the Root certificate. type: string subject: description: The root certificate MUST be self-signed, and so the subject and issuer are the same. type: object properties: commonName: type: string organization: type: string uri: description: The URI at which the CA can be accessed. type: string ctLogs: description: Certificate Transparency Log type: array items: type: object properties: baseURL: description: The base URL which can be used for URLs for clients. type: string hashAlgorithm: description: / The hash algorithm used for the Merkle Tree type: string publicKey: description: PEM encoded public key type: string tLogs: description: Rekor log specifications type: array items: type: object properties: baseURL: description: The base URL which can be used for URLs for clients. type: string hashAlgorithm: description: / The hash algorithm used for the Merkle Tree type: string publicKey: description: PEM encoded public key type: string timestampAuthorities: description: Trusted timestamping authorities type: array items: type: object properties: certChain: description: The certificate chain for this CA in PEM format. Last entry in this chain is the Root certificate. type: string subject: description: The root certificate MUST be self-signed, and so the subject and issuer are the same. type: object properties: commonName: type: string organization: type: string uri: description: The URI at which the CA can be accessed. type: string status: description: Status represents the current state of the TrustRoot. This data may be out of date. type: object properties: annotations: description: Annotations is additional Status fields for the Resource to save some additional State as well as convey more information to the user. This is roughly akin to Annotations on any k8s resource, just the reconciler conveying richer information outwards. type: object x-kubernetes-preserve-unknown-fields: true conditions: description: Conditions the latest available observations of a resource's current state. type: array items: type: object required: - type - status properties: lastTransitionTime: description: LastTransitionTime is the last time the condition transitioned from one status to another. We use VolatileTime in place of metav1.Time to exclude this from creating equality.Semantic differences (all other things held constant). type: string message: description: A human readable message indicating details about the transition. type: string reason: description: The reason for the condition's last transition. type: string severity: description: Severity with which to treat failures of this type of condition. When this is not specified, it defaults to Error. type: string status: description: Status of the condition, one of True, False, Unknown. type: string type: description: Type of condition. type: string observedGeneration: description: ObservedGeneration is the 'Generation' of the Service that was last processed by the controller. type: integer format: int64 ================================================ FILE: config/400-webhook-service.yaml ================================================ # Copyright 2021 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 # # https://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. apiVersion: v1 kind: Service metadata: name: webhook namespace: cosign-system spec: ports: - port: 443 targetPort: 8443 selector: role: webhook ================================================ FILE: config/500-webhook-configuration.yaml ================================================ # Copyright 2021 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 # # https://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. apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: name: policy.sigstore.dev webhooks: - name: policy.sigstore.dev namespaceSelector: # The webhook should only apply to things that opt-in matchExpressions: - key: policy.sigstore.dev/include operator: In values: ["true"] admissionReviewVersions: [v1] clientConfig: service: name: webhook namespace: cosign-system failurePolicy: Fail sideEffects: None timeoutSeconds: 25 --- apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: name: policy.sigstore.dev webhooks: - name: policy.sigstore.dev namespaceSelector: # The webhook should only apply to things that opt-in matchExpressions: - key: policy.sigstore.dev/include operator: In values: ["true"] admissionReviewVersions: [v1] clientConfig: service: name: webhook namespace: cosign-system failurePolicy: Fail sideEffects: None timeoutSeconds: 25 reinvocationPolicy: IfNeeded --- apiVersion: v1 kind: Secret metadata: name: webhook-certs namespace: cosign-system # The data is populated at install time. ================================================ FILE: config/501-policy-webhook-configurations.yaml ================================================ # 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 # # https://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. apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: name: defaulting.clusterimagepolicy.sigstore.dev webhooks: - admissionReviewVersions: - v1 clientConfig: service: name: webhook namespace: cosign-system failurePolicy: Fail matchPolicy: Equivalent name: defaulting.clusterimagepolicy.sigstore.dev sideEffects: None --- apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: name: validating.clusterimagepolicy.sigstore.dev webhooks: - admissionReviewVersions: - v1 clientConfig: service: name: webhook namespace: cosign-system failurePolicy: Fail matchPolicy: Equivalent name: validating.clusterimagepolicy.sigstore.dev sideEffects: None --- ================================================ FILE: config/config-image-policies.yaml ================================================ # 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. apiVersion: v1 kind: ConfigMap metadata: name: config-image-policies namespace: cosign-system data: _example: | ################################ # # # EXAMPLE CONFIGURATION # # # ################################ cluster-image-policy-json: "{\"images\":[{\"glob\":\"ghcr.io/example/*\",\"regex\":\"\"}],\"authorities\":[{\"key\":{\"data\":\"-----BEGIN PUBLIC KEY-----\\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J\\nRCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ==\\n-----END PUBLIC KEY-----\"}}]}" ================================================ FILE: config/config-leader-election.yaml ================================================ # Copyright 2021 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 # # https://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. apiVersion: v1 kind: ConfigMap metadata: name: config-leader-election namespace: cosign-system data: _example: | ################################ # # # EXAMPLE CONFIGURATION # # # ################################ # This block is not actually functional configuration, # but serves to illustrate the available configuration # options and document them in a way that is accessible # to users that `kubectl edit` this config map. # # These sample configuration options may be copied out of # this example block and unindented to be in the data block # to actually change the configuration. # leaseDuration is how long non-leaders will wait to try to acquire the # lock; 15 seconds is the value used by core kubernetes controllers. leaseDuration: "15s" # renewDeadline is how long a leader will try to renew the lease before # giving up; 10 seconds is the value used by core kubernetes controllers. renewDeadline: "10s" # retryPeriod is how long the leader election client waits between tries of # actions; 2 seconds is the value used by core kubernetes controllers. retryPeriod: "2s" # buckets is the number of buckets used to partition key space of each # Reconciler. If this number is M and the replica number of the controller # is N, the N replicas will compete for the M buckets. The owner of a # bucket will take care of the reconciling for the keys partitioned into # that bucket. buckets: "1" ================================================ FILE: config/config-logging.yaml ================================================ # Copyright 2021 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 # # https://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. apiVersion: v1 kind: ConfigMap metadata: name: config-logging namespace: cosign-system data: _example: | ################################ # # # EXAMPLE CONFIGURATION # # # ################################ # This block is not actually functional configuration, # but serves to illustrate the available configuration # options and document them in a way that is accessible # to users that `kubectl edit` this config map. # # These sample configuration options may be copied out of # this example block and unindented to be in the data block # to actually change the configuration. zap-logger-config: | { "level": "info", "development": false, "outputPaths": ["stdout"], "errorOutputPaths": ["stderr"], "encoding": "json", "encoderConfig": { "timeKey": "ts", "levelKey": "level", "nameKey": "logger", "callerKey": "caller", "messageKey": "msg", "stacktraceKey": "stacktrace", "lineEnding": "", "levelEncoder": "", "timeEncoder": "iso8601", "durationEncoder": "", "callerEncoder": "" } } # Log level overrides # Changes are be picked up immediately. loglevel.controller: "info" loglevel.webhook: "info" ================================================ FILE: config/config-observability.yaml ================================================ # Copyright 2021 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 # # https://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. apiVersion: v1 kind: ConfigMap metadata: name: config-observability namespace: cosign-system data: _example: | ################################ # # # EXAMPLE CONFIGURATION # # # ################################ # This block is not actually functional configuration, # but serves to illustrate the available configuration # options and document them in a way that is accessible # to users that `kubectl edit` this config map. # # These sample configuration options may be copied out of # this example block and unindented to be in the data block # to actually change the configuration. # metrics.backend-destination field specifies the system metrics destination. # It supports either prometheus (the default) or stackdriver. # Note: Using stackdriver will incur additional charges metrics.backend-destination: prometheus # metrics.request-metrics-backend-destination specifies the request metrics # destination. If non-empty, it enables queue proxy to send request metrics. # Currently supported values: prometheus, stackdriver. metrics.request-metrics-backend-destination: prometheus # metrics.stackdriver-project-id field specifies the stackdriver project ID. This # field is optional. When running on GCE, application default credentials will be # used if this field is not provided. metrics.stackdriver-project-id: "" ================================================ FILE: config/config-policy-controller.yaml ================================================ # 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. apiVersion: v1 kind: ConfigMap metadata: name: config-policy-controller namespace: cosign-system data: _example: | ################################ # # # EXAMPLE CONFIGURATION # # # ################################ no-match-policy: warn ================================================ FILE: config/config-sigstore-keys.yaml ================================================ # 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. apiVersion: v1 kind: ConfigMap metadata: name: config-sigstore-keys namespace: cosign-system data: _example: | ################################ # # # EXAMPLE CONFIGURATION # # # ################################ my-custom-sigstore-keys: |- {"certificateAuthority":[{"subject":{"organization":"fulcio-organization","commonName":"fulcio-common-name"},"uri":"https://fulcio.example.com","certChain":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCglNSUlGd3pDQ0E2dWdBd0lCQWdJSUs3eGIrcnFZNGdFd0RRWUpLb1pJaHZjTkFRRUxCUUF3ZmpFTU1Bb0dBMVVFCglCaE1EVlZOQk1STXdFUVlEVlFRSUV3cERZV3hwWm05eWJtbGhNUll3RkFZRFZRUUhFdzFUWVc0Z1JuSmhibU5wCgljMk52TVJZd0ZBWURWUVFKRXcwMU5EZ2dUV0Z5YTJWMElGTjBNUTR3REFZRFZRUVJFd1UxTnpJM05ERVpNQmNHCglBMVVFQ2hNUVRHbHVkWGdnUm05MWJtUmhkR2x2YmpBZUZ3MHlNakV5TURnd01qRTNOVEZhRncweU16RXlNRGd3CglNakUzTlRGYU1INHhEREFLQmdOVkJBWVRBMVZUUVRFVE1CRUdBMVVFQ0JNS1EyRnNhV1p2Y201cFlURVdNQlFHCglBMVVFQnhNTlUyRnVJRVp5WVc1amFYTmpiekVXTUJRR0ExVUVDUk1OTlRRNElFMWhjbXRsZENCVGRERU9NQXdHCglBMVVFRVJNRk5UY3lOelF4R1RBWEJnTlZCQW9URUV4cGJuVjRJRVp2ZFc1a1lYUnBiMjR3Z2dJaU1BMEdDU3FHCglTSWIzRFFFQkFRVUFBNElDRHdBd2dnSUtBb0lDQVFDMTQyRWpsZzJReEl3cE5qYmFlVy9mdDlzSDFUWFU2Q1dnCglic3ZWcDc3dlJnY2tTbnBNM1JUQy9nd0V3Skh0WCtHT1RyUDlybzZuRkpOM0czaGNGbmFNSExLZEdyb2Y5aUh1Cgkvdy9sWkx3UXpYelZUKzBaeVp4eXRIQVdHRkJ2bVlNNEozM2pINkRqOVB2cU9Od3RTQlNtWkJQYy9ILzhFdllzCglVenhQV3VraE90b3RTSDNWWERxWjRqbDk2TUxlMCs1ZzJXaTdNeFJYNDRYMVJpUFMxNGJhMUVTNTM4YlRoaGNRCgk0U01qM3VoYmRzQ0lrY203ZUY0RVkzcEVYUXBYRUVHblpHZndZZ1FyKzZjVDA3WmQvV0RNME5YM0t4SDZxUms5CglnRGpQbmZjTXVGYk9UYmZEL251dng2Rk5YNk9VcnpyWlNnbGtMdmNQSUJWT1c3TG40MUxBYjdhWG1iV0xGRUpuCgl1TG9vUHBZWXIrNk5obkZETkdwc0JLR0tyL2t2YlF5REtLc3QzQ0tqOW90UFMxMzYzbmk0MXFub0E3WVdTcXh3Cgl6NDE4NWRLS2MrWTd5dkpRc1JscjZxRzFzTkxPK2M3N2ZTUzVWWkltek5vekJjUmt1TEpGbFgrV0IwdXpnUVU1CglzNDVJWlcrZks5Mm5mdThNbUtqekhSK2lkeXI0T3lqUzBZU04zR01nYzBVUDdLNmhWcGhMZWRBcEZweWtCU0ZHCglVZ2lQWndyVCttR1NWZ21PWHE1bjFkUVRDRDE0bEVoMnF0My9yZmY4ek5jMENNQU5XeWJhTUdCR1E0YmhWVlhlCglSS1l4OXUyUFpqUHY1M3A3WWIvRENkcW5HRUR3L0hDQkRpQ3M0b1llNGRhRTM2eFVvanhEU20zRGFlTkc2OHo5CglSTDdnZlVqQXhRSURBUUFCbzBVd1F6QU9CZ05WSFE4QkFmOEVCQU1DQVFZd0VnWURWUjBUQVFIL0JBZ3dCZ0VCCgkvd0lCQVRBZEJnTlZIUTRFRmdRVWYrbGJOWDBXaDRoK1EwU1J0aFJLK0tmTGpxRXdEUVlKS29aSWh2Y05BUUVMCglCUUFEZ2dJQkFFaEpqYTBaU0t3WGNhT1hDWVJYVEUwNitKYnBlekk1TGV2QmhtYlJRSzc4OVJxMTBKZUFYYTdtCglFVG9SR2xHRkxIMnVEVDExbXNGS3lNM3Y2N0tsRTFTWVZjcUttQ2xZZklWRVlIM0xhMHVJKzlySFpuV2diNEJsCgl5MUI4d2JsS0p6aFlRRDlaNEgvZ3MrQkFzb1JYNVZvRnlJZ2tOQmsxcDNmdGFWQ2JrUXZTME9ZdFlzNWl3NGVLCgljSTcxL0lzVElUM1pwcGo5UjhJR3Nxd0xLZ3pmbnlOY0ZKZHorb2hjNlYyMlBqWk1FQkhDc0hQTzRhdjJMbFdLCgk1WTFmbEwrMmJxVHFibU8vYmpmWDB3NFoxRHVvalJjT1pGN1NINE8zUXUyWTcvNjlnSDdDcDBuaVZDbTV6K1M1CgkwMTFWNlB2TWpybWlFK3hWa3hMSGJZRWdvY2JGaGQ1RGNpTUNYcHZzdURab2phSTNGUkVtQnFpSWhLb2tpM3JiCgl3dUVseWE3OGJNd2taMWtycDc2bldzbzQ3LzArNTFpby9XcmlBZHIwY2ptem9uaG83UnFJRTNEQzc3Q0VNa2FnCgladktTbUwzc2ZmK1dOU3JuUGx6bksxOU5BMno0SW1XOU1zenFQckNUUUdQLy9CQnU3U2Ftem9mVk05ZjRQQUlyCglGVHBuVzZzR2RwQ3pQOEUwV1V1OUIrdmlLcnRmTS85c3huSTlXaGZKUGRyRVAwaVpXM3Zod3ZnUWJLYjVEMk9TCglVNG5yVm92NkJXci9CbmhRSzhJWG8xdHEzajhGQ1JJb2xlWE5oa3M0Z25rT2FEc1cyS3RWcXd0SzNpTzNCdlBiCglMNXcwZ2RMandNTGtlazcyeTYxWHF6NVd4WndOaGw1WWNtQkt1U3ZtVlNIdkE2OEJWU2JCCgktLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgk="}],"tLog":[{"baseURL":"https://rekor.example.com","hashAlgorithm":"sha-256","publicKey":"LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KCU1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRTdEMld2Z3FTenM5anBkSnNPSjVObDZ4ZzhKWG0KCU5tbzdNM2JONytkUWRkdzlJYmMyUjNTVjh0ekJadzByU1Q4RktjbjRhcEplcGNLTTRxVXBZVWVOZnc9PQoJLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCgk=","logID":"rekor-log-id"}],"ctLog":[{"baseURL":"https://ctfe.example.com","hashAlgorithm":"sha-256","publicKey":"LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KCU1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMERBUWNEUWdBRUp2Q0ppNzA3ZnY1dE1KMVUyVFZNWit1TzRkS0cKCWFFY3ZqbENrZ0JDS1hicmt1bVpWMG0wZFNsSzFWMWd4RWl5UTh5NmhrMU14Sk5lMkFaclpVdDdhNHc9PQoJLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCgk=","logID":"ctfe-log-id"}],"timestampAuthorities":[{"subject":{"organization":"tsa-organization","commonName":"tsa-common-name"},"uri":"https://tsa.example.com","certChain":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCglNSUlCekRDQ0FYS2dBd0lCQWdJVWZ5R0tEb0ZhN3k2cy9XMXAxQ2lUbUJSczFlQXdDZ1lJS29aSXpqMEVBd0l3CglNREVPTUF3R0ExVUVDaE1GYkc5allXd3hIakFjQmdOVkJBTVRGVlJsYzNRZ1ZGTkJJRWx1ZEdWeWJXVmthV0YwCglaVEFlRncweU1qRXhNRGt5TURNeE16UmFGdzB6TVRFeE1Ea3lNRE0wTXpSYU1EQXhEakFNQmdOVkJBb1RCV3h2CglZMkZzTVI0d0hBWURWUVFERXhWVVpYTjBJRlJUUVNCVWFXMWxjM1JoYlhCcGJtY3dXVEFUQmdjcWhrak9QUUlCCglCZ2dxaGtqT1BRTUJCd05DQUFSM0tjRHk5andBUlgwckR2eXIrTUdHa0czbjFPQTBNVTUrWmlEbWd1c0Z5azZVCgk2Ym92S1dWTWZEOEo4TlRjSlpFMFJhWUpyOC9kRTlrZ2NJSVhsaE13bzJvd2FEQU9CZ05WSFE4QkFmOEVCQU1DCglCNEF3SFFZRFZSME9CQllFRkhObjVSM2IzTXRVZFNOckZPNDlRNlhEVlNua01COEdBMVVkSXdRWU1CYUFGTkxTCgk2Z25vN09tKytRdDV6SWErSDlvMEhpVDJNQllHQTFVZEpRRUIvd1FNTUFvR0NDc0dBUVVGQndNSU1Bb0dDQ3FHCglTTTQ5QkFNQ0EwZ0FNRVVDSVFDRjBvbG9obnZkVXE2VDcvd1BrMTlaNWFRUC95eFJUakNXWXVobi9UQ3lIZ0lnCglhelYzYWlyNEdSWmJOOWJkWXRjUTdKVUFLcTg5R09odEZmbDZrY29WVXZVPQoJLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQoJLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCglNSUlCMGpDQ0FYaWdBd0lCQWdJVVhwQm1ZSkZGYUdXM2NDOHA2Yi9ESHIxaThJb3dDZ1lJS29aSXpqMEVBd0l3CglLREVPTUF3R0ExVUVDaE1GYkc5allXd3hGakFVQmdOVkJBTVREVlJsYzNRZ1ZGTkJJRkp2YjNRd0hoY05Nakl4CglNVEE1TWpBeU9UTTBXaGNOTXpJeE1UQTVNakF6TkRNMFdqQXdNUTR3REFZRFZRUUtFd1ZzYjJOaGJERWVNQndHCglBMVVFQXhNVlZHVnpkQ0JVVTBFZ1NXNTBaWEp0WldScFlYUmxNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBECglBUWNEUWdBRUtEUERSSXdEUzFaQ3ltdWI2eWFuQ0c1bWEwcURqTHBOb25Edm9vU2tSSEVnVTBUTmliZUpuNk0rCgk1VzYwOGhDdzhud3V1Y01iWFE0MWtOZXVCZWV2eXFONE1IWXdEZ1lEVlIwUEFRSC9CQVFEQWdFR01CTUdBMVVkCglKUVFNTUFvR0NDc0dBUVVGQndNSU1BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0hRWURWUjBPQkJZRUZOTFM2Z25vCgk3T20rK1F0NXpJYStIOW8wSGlUMk1COEdBMVVkSXdRWU1CYUFGQjFudlhwTks3QXVRbGJKK3lhNm5QU3FXaStUCglNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJR2l3cUNJMjl3N0M0VjhUbHRDc2k3MjhzNUR0a2xDUHlTREFTVVN1CglhNXk1QWlFQTQwSWZkbHdmN1VqOHE4TlNENlo0Zy8wanMwdEdOZExTVUoxZG8vV29OMHM9CgktLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCgktLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KCU1JSUJsRENDQVRxZ0F3SUJBZ0lVWVp4OXNTMTRFbjdTdUhET0pKUDRJUG9wTWpVd0NnWUlLb1pJemowRUF3SXcKCUtERU9NQXdHQTFVRUNoTUZiRzlqWVd3eEZqQVVCZ05WQkFNVERWUmxjM1FnVkZOQklGSnZiM1F3SGhjTk1qSXgKCU1UQTVNakF5T1RNMFdoY05Nekl4TVRBNU1qQXpORE0wV2pBb01RNHdEQVlEVlFRS0V3VnNiMk5oYkRFV01CUUcKCUExVUVBeE1OVkdWemRDQlVVMEVnVW05dmREQlpNQk1HQnlxR1NNNDlBZ0VHQ0NxR1NNNDlBd0VIQTBJQUJBYkIKCUIwU1U4Rzc1aFZJVXBoQ2hBNG5mT3dOV1AzNDdUalNjSWRzRVByS1ZuKy9ZMUhtbUxISkRqU2ZuK3hoRUZvRWsKCTdqcWdycW9uNDhpNHhibzd4QXVqUWpCQU1BNEdBMVVkRHdFQi93UUVBd0lCQmpBUEJnTlZIUk1CQWY4RUJUQUQKCUFRSC9NQjBHQTFVZERnUVdCQlFkWjcxNlRTdXdMa0pXeWZzbXVwejBxbG92a3pBS0JnZ3Foa2pPUFFRREFnTkkKCUFEQkZBaUJlNVA1NmZvcW1GY1pBVnBFZUFPRlpyQWxFaXEwNUNDcE1OWWg1RWpMdm1BSWhBS05GNnhJVjV1RmQKCXBTVEpzQXd6alc3OENLUW03cW9sMHVQbVBQdTZtTmF3CgktLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0t"}]} ================================================ FILE: config/dummy.go ================================================ // 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. // Package config is a placeholder that allows us to pull in config files // via go mod vendor. package config ================================================ FILE: config/kustomization.yaml ================================================ # 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 # # https://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. apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - 100-namespace.yaml - 200-serviceaccount.yaml - 200-role.yaml - 200-clusterrole.yaml - 201-rolebinding.yaml - 201-clusterrolebinding.yaml - 300-clusterimagepolicy.yaml - 300-trustroot.yaml - 400-webhook-service.yaml - 500-webhook-configuration.yaml - 501-policy-webhook-configurations.yaml - config-observability.yaml - config-logging.yaml - config-leader-election.yaml - config-image-policies.yaml - config-sigstore-keys.yaml - config-policy-controller.yaml ================================================ FILE: config/webhook.yaml ================================================ # Copyright 2021 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 # # https://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. --- --- apiVersion: apps/v1 kind: Deployment metadata: name: webhook namespace: cosign-system spec: selector: matchLabels: role: webhook template: metadata: labels: role: webhook spec: # To avoid node becoming SPOF, spread our replicas to different nodes. affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - podAffinityTerm: labelSelector: matchLabels: role: webhook topologyKey: kubernetes.io/hostname weight: 100 serviceAccountName: webhook containers: - name: webhook # This is the Go import path for the binary that is containerized # and substituted here. image: ko://github.com/sigstore/policy-controller/cmd/webhook args: [ # Uncomment these to initialize with a custom TUF root. # TODO: How to specify the entire TUF directory for multiple # TUF roots. #"--tuf-mirror", "http://tuf.tuf-system.svc", #"--tuf-root", "/var/run/tuf/root.json", # Uncomment to customize ClusterImagePolicy resync period # "--policy-resync-period", "10h", ] resources: requests: cpu: 40m memory: 40Mi limits: cpu: 400m memory: 400Mi env: - name: SYSTEM_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: CONFIG_LOGGING_NAME value: config-logging - name: METRICS_DOMAIN value: sigstore.dev/policy - name: WEBHOOK_NAME value: webhook - name: KUBERNETES_MIN_VERSION value: "1.21.0" - name: HOME value: "/var/run/sigstore" securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true runAsNonRoot: true capabilities: drop: - ALL volumeMounts: - name: homedir mountPath: "/var/run/sigstore" - name: tuf-root mountPath: "/var/run/tuf" readOnly: true readinessProbe: &probe failureThreshold: 6 initialDelaySeconds: 20 periodSeconds: 1 httpGet: scheme: HTTPS port: 8443 httpHeaders: - name: k-kubelet-probe value: "webhook" livenessProbe: *probe # Our webhook should gracefully terminate by lame ducking first, set this to a sufficiently # high value that we respect whatever value it has configured for the lame duck grace period. terminationGracePeriodSeconds: 300 volumes: - emptyDir: {} name: homedir - name: tuf-root secret: secretName: tuf-root # This is marked as optional, since if you are using public # instance, TUF root is built in to the cosign container. optional: true items: - key: root path: root.json --- ================================================ FILE: docs/api-types/index-v1alpha1.md ================================================ # API Documentation (v1alpha1) > This document is automatically generated from the API definition in the code. ## Table of Contents * [CertificateAuthority](#certificateauthority) * [DistinguishedName](#distinguishedname) * [Remote](#remote) * [Repository](#repository) * [SigstoreKeys](#sigstorekeys) * [TransparencyLogInstance](#transparencyloginstance) * [TrustRoot](#trustroot) * [TrustRootList](#trustrootlist) * [TrustRootSpec](#trustrootspec) * [Attestation](#attestation) * [Authority](#authority) * [ClusterImagePolicy](#clusterimagepolicy) * [ClusterImagePolicyList](#clusterimagepolicylist) * [ClusterImagePolicySpec](#clusterimagepolicyspec) * [ConfigMapReference](#configmapreference) * [Identity](#identity) * [ImagePattern](#imagepattern) * [KeyRef](#keyref) * [KeylessRef](#keylessref) * [MatchResource](#matchresource) * [Policy](#policy) * [RFC3161Timestamp](#rfc3161timestamp) * [RemotePolicy](#remotepolicy) * [Source](#source) * [StaticRef](#staticref) * [TLog](#tlog) ## CertificateAuthority | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | subject | The root certificate MUST be self-signed, and so the subject and issuer are the same. | [DistinguishedName](#distinguishedname) | true | | uri | The URI at which the CA can be accessed. | apis.URL | true | | certChain | The certificate chain for this CA in PEM format. Last entry in this chain is the Root certificate. | []byte | true | [Back to TOC](#table-of-contents) ## DistinguishedName | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | organization | | string | true | | commonName | | string | true | [Back to TOC](#table-of-contents) ## Remote Remote specifies the TUF with trusted initial root and remote mirror where to fetch updates from. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | root | Root is the base64 encoded, json trusted initial root. | []byte | true | | mirror | Mirror is the remote mirror, for example: https://tuf-repo-cdn.sigstore.dev | apis.URL | true | | targets | Targets is where the targets live off of the root of the Remote If not specified 'targets' is defaulted. | string | false | | trustedRootTarget | TrustedRootTarget is the name of the target containing the JSON trusted root. If not specified, `trusted_root.json` is used. | string | false | [Back to TOC](#table-of-contents) ## Repository Repository specifies an airgapped TUF. Specifies the trusted initial root as well as a serialized repository. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | root | Root is the base64 encoded, json trusted initial root. | []byte | true | | mirrorFS | MirrorFS is the base64 tarred, gzipped, and base64 encoded remote repository that can be used for example in air-gap environments. Will not make outbound network connections, and must then be kept up to date in some other manner. The repository must contain metadata as well as targets. | []byte | true | | targets | Targets is where the targets live off of the root of the Repository above. If not specified 'targets' is defaulted. | string | false | | trustedRootTarget | TrustedRootTarget is the name of the target containing the JSON trusted root. If not specified, `trusted_root.json` is used. | string | false | [Back to TOC](#table-of-contents) ## SigstoreKeys SigstoreKeys contains all the necessary Keys and Certificates for validating against a specific instance of Sigstore. This is used for bringing your own trusted keys/certs. and see how easy it is to replace with protos instead of our custom defs above. https://github.com/sigstore/protobuf-specs/pull/5 And in particular: https://github.com/sigstore/protobuf-specs/pull/5/files#diff-b1f89b7fd3eb27b519380b092a2416f893a96fbba3f8c90cfa767e7687383ad4R70 Well, not the multi-root, but one instance of that is exactly the SigstoreKeys. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | certificateAuthorities | Trusted certificate authorities (e.g Fulcio). | [][CertificateAuthority](#certificateauthority) | true | | tLogs | Rekor log specifications | [][TransparencyLogInstance](#transparencyloginstance) | false | | ctLogs | Certificate Transparency Log | [][TransparencyLogInstance](#transparencyloginstance) | false | | timestampAuthorities | Trusted timestamping authorities | [][CertificateAuthority](#certificateauthority) | false | [Back to TOC](#table-of-contents) ## TransparencyLogInstance TransparencyLogInstance describes the immutable parameters from a transparency log. See https://www.rfc-editor.org/rfc/rfc9162.html#name-log-parameters for more details. The incluced parameters are the minimal set required to identify a log, and verify an inclusion promise. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | baseURL | The base URL which can be used for URLs for clients. | apis.URL | true | | hashAlgorithm | / The hash algorithm used for the Merkle Tree | string | true | | publicKey | PEM encoded public key | []byte | true | [Back to TOC](#table-of-contents) ## TrustRoot TrustRoot defines the keys and certificates that are trusted for validating against. These can be specified as TUF Roots, serialized TUF repository (for air-gap scenarios), as well as serialized keys/certificates, for bring your own keys/certs. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | metadata | | [metav1.ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta) | true | | spec | Spec is the definition for a trust root. This is either a TUF root and remote or local repository. You can also bring your own keys/certs here. | [TrustRootSpec](#trustrootspec) | true | | status | Status represents the current state of the TrustRoot. This data may be out of date. | [TrustRootStatus](#trustrootstatus) | false | [Back to TOC](#table-of-contents) ## TrustRootList TrustRootList is a list of TrustRoot resources | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | metadata | | [metav1.ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#listmeta-v1-meta) | true | | items | | [][TrustRoot](#trustroot) | true | [Back to TOC](#table-of-contents) ## TrustRootSpec TrustRootSpec defines a trusted Root. This is typically either a TUF Root or a bring your own keys variation. It specifies either: root.json and remote or fully gzipped / tarred directory containing root and metadata directories or serialized keys / certificate chains (bring your own keys). | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | remote | Remote specifies initial root of trust & remote mirror. | [Remote](#remote) | false | | repository | Repository contains the serialized TUF remote repository. | [Repository](#repository) | false | | sigstoreKeys | SigstoreKeys contains the serialized keys. | [SigstoreKeys](#sigstorekeys) | false | [Back to TOC](#table-of-contents) ## TrustRootStatus TrustRootStatus represents the current state of a TrustRoot. ## Attestation Attestation defines the type of attestation to validate and optionally apply a policy decision to it. Authority block is used to verify the specified attestation types, and if Policy is specified, then it's applied only after the validation of the Attestation signature has been verified. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | name | Name of the attestation. These can then be referenced at the CIP level policy. | string | true | | predicateType | PredicateType defines which predicate type to verify. Matches cosign verify-attestation options. | string | true | | policy | Policy defines all of the matching signatures, and all of the matching attestations (whose attestations are verified). | [Policy](#policy) | false | [Back to TOC](#table-of-contents) ## Authority | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | name | Name is the name for this authority. Used by the CIP Policy validator to be able to reference matching signature or attestation verifications. If not specified, the name will be authority- | string | true | | key | Key defines the type of key to validate the image. | [KeyRef](#keyref) | false | | keyless | Keyless sets the configuration to verify the authority against a Fulcio instance. | [KeylessRef](#keylessref) | false | | static | Static specifies that signatures / attestations are not validated but instead a static policy is applied against matching images. | [StaticRef](#staticref) | false | | source | Sources sets the configuration to specify the sources from where to consume the signature and attestations. | [][Source](#source) | false | | ctlog | CTLog sets the configuration to verify the authority against a Rekor instance. | [TLog](#tlog) | false | | attestations | Attestations is a list of individual attestations for this authority, once the signature for this authority has been verified. | [][Attestation](#attestation) | false | | rfc3161timestamp | RFC3161Timestamp sets the configuration to verify the signature timestamp against a RFC3161 time-stamping instance. | [RFC3161Timestamp](#rfc3161timestamp) | false | | signatureFormat | SignatureFormat specifies the format the authority expects. Supported formats are \"legacy\" and \"bundle\". If not specified, the default is \"legacy\" (cosign's default). | string | false | [Back to TOC](#table-of-contents) ## ClusterImagePolicy ClusterImagePolicy defines the images that go through verification and the authorities used for verification | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | metadata | | [metav1.ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta) | true | | spec | Spec holds the desired state of the ClusterImagePolicy (from the client). | [ClusterImagePolicySpec](#clusterimagepolicyspec) | true | | status | Status represents the current state of the ClusterImagePolicy. This data may be out of date. | [ClusterImagePolicyStatus](#clusterimagepolicystatus) | false | [Back to TOC](#table-of-contents) ## ClusterImagePolicyList ClusterImagePolicyList is a list of ClusterImagePolicy resources | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | metadata | | [metav1.ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#listmeta-v1-meta) | true | | items | | [][ClusterImagePolicy](#clusterimagepolicy) | true | [Back to TOC](#table-of-contents) ## ClusterImagePolicySpec ClusterImagePolicySpec defines a list of images that should be verified | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | images | Images defines the patterns of image names that should be subject to this policy. | [][ImagePattern](#imagepattern) | true | | authorities | Authorities defines the rules for discovering and validating signatures. | [][Authority](#authority) | false | | policy | Policy is an optional policy that can be applied against all the successfully validated Authorities. If no authorities pass, this does not even get evaluated, as the Policy is considered failed. | [Policy](#policy) | false | | mode | Mode controls whether a failing policy will be rejected (not admitted), or if errors are converted to Warnings. enforce - Reject (default) warn - allow but warn | string | false | | match | Match allows selecting resources based on their properties. | [][MatchResource](#matchresource) | false | [Back to TOC](#table-of-contents) ## ClusterImagePolicyStatus ClusterImagePolicyStatus represents the current state of a ClusterImagePolicy. ## ConfigMapReference ConfigMapReference is cut&paste from SecretReference, but for the life of me couldn't find one in the public types. If there's one, use it. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | name | Name is unique within a namespace to reference a configmap resource. | string | false | | namespace | Namespace defines the space within which the configmap name must be unique. | string | false | | key | Key defines the key to pull from the configmap. | string | false | [Back to TOC](#table-of-contents) ## Identity Identity may contain the issuer and/or the subject found in the transparency log. Issuer/Subject uses a strict match, while IssuerRegExp and SubjectRegExp apply a regexp for matching. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | issuer | Issuer defines the issuer for this identity. | string | false | | subject | Subject defines the subject for this identity. | string | false | | issuerRegExp | IssuerRegExp specifies a regular expression to match the issuer for this identity. | string | false | | subjectRegExp | SubjectRegExp specifies a regular expression to match the subject for this identity. | string | false | [Back to TOC](#table-of-contents) ## ImagePattern ImagePattern defines a pattern and its associated authorties If multiple patterns match a particular image, then ALL of those authorities must be satisfied for the image to be admitted. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | glob | Glob defines a globbing pattern. | string | true | [Back to TOC](#table-of-contents) ## KeyRef This references a public verification key stored in a secret in the cosign-system namespace. A KeyRef must specify only one of SecretRef, Data or KMS | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | secretRef | SecretRef sets a reference to a secret with the key. | [v1.SecretReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#secretreference-v1-core) | false | | data | Data contains the inline public key | string | false | | kms | KMS contains the KMS url of the public key Supported formats differ based on the KMS system used. | string | false | | hashAlgorithm | HashAlgorithm always defaults to sha256 if the algorithm hasn't been explicitly set | string | false | [Back to TOC](#table-of-contents) ## KeylessRef KeylessRef contains location of the validating certificate and the identities against which to verify. KeylessRef will contain either the URL to the verifying certificate, or it will contain the certificate data inline or in a secret. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | url | URL defines a url to the keyless instance. | apis.URL | false | | identities | Identities sets a list of identities. | [][Identity](#identity) | true | | ca-cert | CACert sets a reference to CA certificate | [KeyRef](#keyref) | false | | trustRootRef | Use the Certificate Chain from the referred TrustRoot.CertificateAuthorities and TrustRoot.CTLog | string | false | | insecureIgnoreSCT | InsecureIgnoreSCT omits verifying if a certificate contains an embedded SCT | bool | false | [Back to TOC](#table-of-contents) ## MatchResource MatchResource allows selecting resources based on its version, group and resource. It is also possible to select resources based on a list of matching labels. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | selector | | [metav1.LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#labelselector-v1-meta) | false | [Back to TOC](#table-of-contents) ## Policy Policy specifies a policy to use for Attestation or the CIP validation (iff at least one authority matches). Exactly one of Data, URL, or ConfigMapReference must be specified. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | type | Which kind of policy this is, currently only rego or cue are supported. Furthermore, only cue is tested :) | string | true | | data | Data contains the policy definition. | string | false | | remote | Remote defines the url to a policy. | [RemotePolicy](#remotepolicy) | false | | configMapRef | ConfigMapRef defines the reference to a configMap with the policy definition. | [ConfigMapReference](#configmapreference) | false | | fetchConfigFile | FetchConfigFile controls whether ConfigFile will be fetched and made available for CIP level policy evaluation. Note that this only gets evaluated (and hence fetched) iff at least one authority matches. The ConfigFile will then be available in this format: https://github.com/opencontainers/image-spec/blob/main/config.md | bool | false | | includeSpec | IncludeSpec controls whether resource `Spec` will be included and made available for CIP level policy evaluation. Note that this only gets evaluated iff at least one authority matches. Also note that because Spec may be of a different shape depending on the resource being evaluatied (see MatchResource for filtering) you might want to configure these to match the policy file to ensure the shape of the Spec is what you expect when evaling the policy. | bool | false | | includeObjectMeta | IncludeObjectMeta controls whether the ObjectMeta will be included and made available for CIP level policy evalutation. Note that this only gets evaluated iff at least one authority matches. | bool | false | | includeTypeMeta | IncludeTypeMeta controls whether the TypeMeta will be included and made available for CIP level policy evalutation. Note that this only gets evaluated iff at least one authority matches. | bool | false | [Back to TOC](#table-of-contents) ## RFC3161Timestamp RFC3161Timestamp specifies the URL to a RFC3161 time-stamping server that holds the time-stamped verification for the signature | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | trustRootRef | Use the Certificate Chain from the referred TrustRoot.TimeStampAuthorities | string | false | [Back to TOC](#table-of-contents) ## RemotePolicy RemotePolicy defines all the properties to fetch a remote policy | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | url | URL to the policy data. | apis.URL | false | | sha256sum | Sha256sum defines the exact sha256sum computed out of the 'body' of the http response. | string | false | [Back to TOC](#table-of-contents) ## Source Source specifies the location of the signature / attestations. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | oci | OCI defines the registry from where to pull the signature / attestations. | string | false | | signaturePullSecrets | SignaturePullSecrets is an optional list of references to secrets in the same namespace as the deploying resource for pulling any of the signatures used by this Source. | [][v1.LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#localobjectreference-v1-core) | false | | tagPrefix | TagPrefix is an optional prefix that signature and attestations have. This is the 'tag based discovery' and in the future once references are fully supported that should likely be the preferred way to handle these. | string | false | [Back to TOC](#table-of-contents) ## StaticRef StaticRef specifies that signatures / attestations are not validated but instead a static policy is applied against matching images. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | action | Action defines how to handle a matching policy. | string | true | | message | For fail actions, emit an optional custom message. This only makes sense for 'fail' action because on 'pass' there's no place to jot down the message. | string | false | [Back to TOC](#table-of-contents) ## TLog TLog specifies the URL to a transparency log that holds the signature and public key information | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | url | URL sets the url to the rekor instance (by default the public rekor.sigstore.dev) | apis.URL | false | | trustRootRef | Use the Public Key from the referred TrustRoot.TLog | string | false | [Back to TOC](#table-of-contents) ================================================ FILE: docs/api-types/index.md ================================================ # API Documentation (v1beta1) > This document is automatically generated from the API definition in the code. ## Table of Contents * [Attestation](#attestation) * [Authority](#authority) * [ClusterImagePolicy](#clusterimagepolicy) * [ClusterImagePolicyList](#clusterimagepolicylist) * [ClusterImagePolicySpec](#clusterimagepolicyspec) * [ConfigMapReference](#configmapreference) * [Identity](#identity) * [ImagePattern](#imagepattern) * [KeyRef](#keyref) * [KeylessRef](#keylessref) * [MatchResource](#matchresource) * [Policy](#policy) * [RFC3161Timestamp](#rfc3161timestamp) * [RemotePolicy](#remotepolicy) * [Source](#source) * [StaticRef](#staticref) * [TLog](#tlog) ## Attestation Attestation defines the type of attestation to validate and optionally apply a policy decision to it. Authority block is used to verify the specified attestation types, and if Policy is specified, then it's applied only after the validation of the Attestation signature has been verified. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | name | Name of the attestation. These can then be referenced at the CIP level policy. | string | true | | predicateType | PredicateType defines which predicate type to verify. Matches cosign verify-attestation options. | string | true | | policy | Policy defines all of the matching signatures, and all of the matching attestations (whose attestations are verified). | [Policy](#policy) | false | [Back to TOC](#table-of-contents) ## Authority The authorities block defines the rules for discovering and validating signatures. Signatures are cryptographically verified using one of the \"key\" or \"keyless\" fields. When multiple authorities are specified, any of them may be used to source the valid signature we are looking for to admit an image. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | name | Name is the name for this authority. Used by the CIP Policy validator to be able to reference matching signature or attestation verifications. If not specified, the name will be authority- | string | true | | key | Key defines the type of key to validate the image. | [KeyRef](#keyref) | false | | keyless | Keyless sets the configuration to verify the authority against a Fulcio instance. | [KeylessRef](#keylessref) | false | | static | Static specifies that signatures / attestations are not validated but instead a static policy is applied against matching images. | [StaticRef](#staticref) | false | | source | Sources sets the configuration to specify the sources from where to consume the signatures. | [][Source](#source) | false | | ctlog | CTLog sets the configuration to verify the authority against a Rekor instance. | [TLog](#tlog) | false | | attestations | Attestations is a list of individual attestations for this authority, once the signature for this authority has been verified. | [][Attestation](#attestation) | false | | rfc3161timestamp | RFC3161Timestamp sets the configuration to verify the signature timestamp against a RFC3161 time-stamping instance. | [RFC3161Timestamp](#rfc3161timestamp) | false | | signatureFormat | SignatureFormat specifies the format the authority expects. Supported formats are \"legacy\" and \"bundle\". If not specified, the default is \"legacy\" (cosign's default). | string | false | [Back to TOC](#table-of-contents) ## ClusterImagePolicy ClusterImagePolicy defines the images that go through verification and the authorities used for verification | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | metadata | | [metav1.ObjectMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#objectmeta-v1-meta) | true | | spec | Spec holds the desired state of the ClusterImagePolicy (from the client). | [ClusterImagePolicySpec](#clusterimagepolicyspec) | true | | status | Status represents the current state of the ClusterImagePolicy. This data may be out of date. | [ClusterImagePolicyStatus](#clusterimagepolicystatus) | false | [Back to TOC](#table-of-contents) ## ClusterImagePolicyList ClusterImagePolicyList is a list of ClusterImagePolicy resources | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | metadata | | [metav1.ListMeta](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#listmeta-v1-meta) | true | | items | | [][ClusterImagePolicy](#clusterimagepolicy) | true | [Back to TOC](#table-of-contents) ## ClusterImagePolicySpec ClusterImagePolicySpec defines a list of images that should be verified | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | images | Images defines the patterns of image names that should be subject to this policy. | [][ImagePattern](#imagepattern) | true | | authorities | Authorities defines the rules for discovering and validating signatures. | [][Authority](#authority) | false | | policy | Policy is an optional policy that can be applied against all the successfully validated Authorities. If no authorities pass, this does not even get evaluated, as the Policy is considered failed. | [Policy](#policy) | false | | mode | Mode controls whether a failing policy will be rejected (not admitted), or if errors are converted to Warnings. enforce - Reject (default) warn - allow but warn | string | false | | match | Match allows selecting resources based on their properties. | [][MatchResource](#matchresource) | false | [Back to TOC](#table-of-contents) ## ClusterImagePolicyStatus ClusterImagePolicyStatus represents the current state of a ClusterImagePolicy. ## ConfigMapReference ConfigMapReference is cut&paste from SecretReference, but for the life of me couldn't find one in the public types. If there's one, use it. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | name | Name is unique within a namespace to reference a configmap resource. | string | false | | namespace | Namespace defines the space within which the configmap name must be unique. | string | false | | key | Key defines the key to pull from the configmap. | string | false | [Back to TOC](#table-of-contents) ## Identity Identity may contain the issuer and/or the subject found in the transparency log. Issuer/Subject uses a strict match, while IssuerRegExp and SubjectRegExp apply a regexp for matching. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | issuer | Issuer defines the issuer for this identity. | string | false | | subject | Subject defines the subject for this identity. | string | false | | issuerRegExp | IssuerRegExp specifies a regular expression to match the issuer for this identity. | string | false | | subjectRegExp | SubjectRegExp specifies a regular expression to match the subject for this identity. | string | false | [Back to TOC](#table-of-contents) ## ImagePattern ImagePattern defines a pattern and its associated authorties If multiple patterns match a particular image, then ALL of those authorities must be satisfied for the image to be admitted. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | glob | Glob defines a globbing pattern. | string | true | [Back to TOC](#table-of-contents) ## KeyRef This references a public verification key stored in a secret in the cosign-system namespace. A KeyRef must specify only one of SecretRef, Data or KMS | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | secretRef | SecretRef sets a reference to a secret with the key. | [v1.SecretReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#secretreference-v1-core) | false | | data | Data contains the inline public key. | string | false | | kms | KMS contains the KMS url of the public key Supported formats differ based on the KMS system used. | string | false | | hashAlgorithm | HashAlgorithm always defaults to sha256 if the algorithm hasn't been explicitly set | string | false | [Back to TOC](#table-of-contents) ## KeylessRef KeylessRef contains location of the validating certificate and the identities against which to verify. KeylessRef will contain either the URL to the verifying certificate, or it will contain the certificate data inline or in a secret. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | url | URL defines a url to the keyless instance. | apis.URL | false | | identities | Identities sets a list of identities. | [][Identity](#identity) | true | | ca-cert | CACert sets a reference to CA certificate | [KeyRef](#keyref) | false | | trustRootRef | Use the Certificate Chain from the referred TrustRoot.CertificateAuthorities and TrustRoot.CTLog | string | false | | insecureIgnoreSCT | InsecureIgnoreSCT omits verifying if a certificate contains an embedded SCT | bool | false | [Back to TOC](#table-of-contents) ## MatchResource MatchResource allows selecting resources based on its version, group and resource. It is also possible to select resources based on a list of matching labels. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | selector | | [metav1.LabelSelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#labelselector-v1-meta) | false | [Back to TOC](#table-of-contents) ## Policy Policy specifies a policy to use for Attestation or the CIP validation (iff at least one authority matches). Exactly one of Data, URL, or ConfigMapReference must be specified. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | type | Which kind of policy this is, currently only rego or cue are supported. Furthermore, only cue is tested :) | string | true | | data | Data contains the policy definition. | string | false | | remote | Remote defines the url to a policy. | [RemotePolicy](#remotepolicy) | false | | configMapRef | ConfigMapRef defines the reference to a configMap with the policy definition. | [ConfigMapReference](#configmapreference) | false | | fetchConfigFile | FetchConfigFile controls whether ConfigFile will be fetched and made available for CIP level policy evaluation. Note that this only gets evaluated (and hence fetched) iff at least one authority matches. The ConfigFile will then be available in this format: https://github.com/opencontainers/image-spec/blob/main/config.md | bool | false | | includeSpec | IncludeSpec controls whether resource `Spec` will be included and made available for CIP level policy evaluation. Note that this only gets evaluated iff at least one authority matches. Also note that because Spec may be of a different shape depending on the resource being evaluatied (see MatchResource for filtering) you might want to configure these to match the policy file to ensure the shape of the Spec is what you expect when evaling the policy. | bool | false | | includeObjectMeta | IncludeObjectMeta controls whether the ObjectMeta will be included and made available for CIP level policy evalutation. Note that this only gets evaluated iff at least one authority matches. | bool | false | | includeTypeMeta | IncludeTypeMeta controls whether the TypeMeta will be included and made available for CIP level policy evalutation. Note that this only gets evaluated iff at least one authority matches. | bool | false | [Back to TOC](#table-of-contents) ## RFC3161Timestamp RFC3161Timestamp specifies the URL to a RFC3161 time-stamping server that holds the time-stamped verification for the signature | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | trustRootRef | Use the Certificate Chain from the referred TrustRoot.TimeStampAuthorities | string | false | [Back to TOC](#table-of-contents) ## RemotePolicy RemotePolicy defines all the properties to fetch a remote policy | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | url | URL to the policy data. | apis.URL | false | | sha256sum | Sha256sum defines the exact sha256sum computed out of the 'body' of the http response. | string | false | [Back to TOC](#table-of-contents) ## Source Source specifies the location of the signature / attestations. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | oci | OCI defines the registry from where to pull the signature / attestations. | string | false | | signaturePullSecrets | SignaturePullSecrets is an optional list of references to secrets in the same namespace as the deploying resource for pulling any of the signatures used by this Source. | [][v1.LocalObjectReference](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#localobjectreference-v1-core) | false | | tagPrefix | TagPrefix is an optional prefix that signature and attestations have. This is the 'tag based discovery' and in the future once references are fully supported that should likely be the preferred way to handle these. | string | false | [Back to TOC](#table-of-contents) ## StaticRef StaticRef specifies that signatures / attestations are not validated but instead a static policy is applied against matching images. | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | action | Action defines how to handle a matching policy. | string | true | | message | For fail actions, emit an optional custom message | string | false | [Back to TOC](#table-of-contents) ## TLog TLog specifies the URL to a transparency log that holds the signature and public key information | Field | Description | Scheme | Required | | ----- | ----------- | ------ | -------- | | url | URL sets the url to the rekor instance (by default the public rekor.sigstore.dev) | apis.URL | false | | trustRootRef | Use the Public Key from the referred TrustRoot.TLog | string | false | [Back to TOC](#table-of-contents) ================================================ FILE: examples/README.md ================================================ # Examples *Note: adding a new example here? Make sure to add test for it in [`../.github/workflows/policy-tester-examples.yml`](../.github/workflows/policy-tester-examples.yml).* ## Prerequisites Make sure that the `policy-tester` CLI is built. At the root of this repo, run the following: ``` make policy-tester ``` ## Validating a policy Set the `POLICY` and `IMAGE` environment variables appropriately, pointing to the example policy and image to test: ``` POLICY="policies/some-policy.yaml" IMAGE="r.example.com/myapp:v0.1.0" ``` Then run the following to validate the image against the policy: ``` ../policy-tester --policy "${POLICY}" --image "${IMAGE}" ``` ## Example policies ### custom-key-attestation-sbom-spdxjson Source: [policies/custom-key-attestation-sbom-spdxjson.yaml](./policies/custom-key-attestation-sbom-spdxjson.yaml) Assert that all images must have a signed SPDX SBOM (spdxjson) attestation using a custom key. ``` POLICY="policies/custom-key-attestation-sbom-spdxjson.yaml" ``` #### How to satisfy this policy First, use your favorite tool to generate an [SPDX](https://spdx.dev/) SBOM. For example purposes, you can use [`sboms/example.spdx.json`](./sboms/example.spdx.json). Then attach it to your image using [cosign attest](https://github.com/sigstore/cosign/blob/main/doc/cosign_attest.md) with the flag `--type spdxjson`, signing it using the private key located at [`keys/cosign.key`](./keys/cosign.key): ``` export COSIGN_PASSWORD="" cosign attest --yes --type spdxjson \ --predicate sboms/example.spdx.json \ --key keys/cosign.key \ "${IMAGE}" ``` ### keyless-attestation-sbom-spdxjson Source: [policies/keyless-attestation-sbom-spdxjson.yaml](./policies/keyless-attestation-sbom-spdxjson.yaml) Assert that all images must have a "keyless" signed SPDX SBOM (spdxjson) attestation against the public Fulcio root. ``` POLICY="policies/keyless-attestation-sbom-spdxjson.yaml" ``` #### How to satisfy this policy First, use your favorite tool to generate an [SPDX](https://spdx.dev/) SBOM. For example purposes, you can use [`sboms/example.spdx.json`](./sboms/example.spdx.json). Then attach it to your image using [cosign attest](https://github.com/sigstore/cosign/blob/main/doc/cosign_attest.md) with the flag `--type spdxjson`, signing "keyless" against the public Fulcio root: ``` cosign attest --yes --type spdxjson \ --predicate sboms/example.spdx.json \ "${IMAGE}" ``` ### signed-by-aws-kms-key Source: [policies/signed-by-aws-kms.yaml](./policies/signed-by-aws-kms.yaml) Asserts that images have been signed by a specific AWS KMS key. ``` POLICY="policies/signed-by-aws-kms.yaml" ``` #### How to satisfy this policy Create (or find) an AWS KMS key to sign your container images and note the ARN of the key. ```sh $ aws kms create-key \ --description "Container signing key" \ --key-spec ECC_NIST_P256 \ --key-usage SIGN_VERIFY { "KeyMetadata": { "AWSAccountId": "...." "Arn": "arn:aws:kms:us-west-2:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab", .... } } ``` Next sign your container using the KMS key and `cosign` ``` cosign sign --key "awskms:///<< arn of kms key >>" "${IMAGE}" ``` ### signed-by-gcp-kms-key Source: [policies/signed-by-gcp-kms.yaml](./policies/signed-by-gcp-kms.yaml) Asserts that images have been signed by a specific GCP KMS key. ``` POLICY="policies/signed-by-gcp-kms.yaml" ``` #### How to satisfy this policy Create the GCP KMS keyring and key to sign your container images. ```sh gcloud kms keyrings create ${KEY_RING} \ --location ${REGION} gcloud kms keys create ${KEY_NAME} \ --keyring ${KEY_RING} \ --location ${REGION} \ --purpose asymmetric-signing \ --default-algorithm ec-sign-p256-sha256 ``` Next sign your container using the KMS key and `cosign`. ```sh gcloud auth application-default login cosign generate-key-pair \ --kms gcpkms://projects/${PROJECT_ID}/locations/${REGION}/keyRings/${KEY_RING}/cryptoKeys/${KEY_NAME} cosign sign \ --key gcpkms://projects/${PROJECT_ID}/locations/${REGION}/keyRings/${KEY_RING}/cryptoKeys/${KEY_NAME} \ ${IMAGE} ``` To satisfy the policy, ensure that the policy controller must have `roles/cloudkms.viewer` and `roles/cloudkms.verifier` IAM permissions on the relevant service account. Also, the GKE cluster should have the `https://www.googleapis.com/auth/cloudkms` scope. ### signed-by-github-actions Source: [policies/signed-by-github-actions.yaml](./policies/signed-by-github-actions.yaml) Asserts that images have been signed by a specific Github Actions workflow using keyless signing. ``` POLICY="policies/signed-by-github-actions.yaml" ``` #### How to satisfy this policy To satisfy this policy you must sign your container image from within a [Github Actions](https://docs.github.com/en/actions) workflow. Sigstore publishes a cosign installer action that makes this easy. Here is an example workflow for signing ```yaml jobs: sign_action: runs-on: ubuntu-latest permissions: contents: read id-token: write # NB: needed for signing the images with GitHub OIDC Token name: Install Cosign and sign image steps: - uses: actions/checkout@master with: fetch-depth: 1 - name: Install Cosign uses: sigstore/cosign-installer@main - name: Sign the images with GitHub OIDC Token run: cosign sign ${IMAGE} ``` To satisfy the policy, ensure that the path and branch of the workflow match the workflow URI in the policy. ================================================ FILE: examples/keys/cosign.key ================================================ -----BEGIN ENCRYPTED COSIGN PRIVATE KEY----- eyJrZGYiOnsibmFtZSI6InNjcnlwdCIsInBhcmFtcyI6eyJOIjozMjc2OCwiciI6 OCwicCI6MX0sInNhbHQiOiJnQlZkM21FMnA3OHhsbUFPSlZkRmcwcXdpcnAwTEMy a2ROdkFiTW9lWVpRPSJ9LCJjaXBoZXIiOnsibmFtZSI6Im5hY2wvc2VjcmV0Ym94 Iiwibm9uY2UiOiJGNDdDZEN3K3U1TXRMMVd2K21wT0tWbnpkTmliaWh2USJ9LCJj aXBoZXJ0ZXh0IjoiMUI4Q0o2ZC9JY1hIeTBqaEZrbkk4RXdCUXRuOFkyN2kzY0wz RURLVUFheUVDR3BiTWRsUXFFOGlGMVJaRW1BWTIwa0plV1VhdkVUMURocFZzZWVJ ZjYraW1SK3c2V0lXWFB0MWJJNCthQ3RCVU1jZ21QN05IQXdRY0dZbGlXZmVRWG12 Zlh2bVJ1bFlwNnZBaUh4c3EvMFUxNU9qNjRCcWE4OE5TK010WWVIQjVrd1ZVcmJB VGYwaEpnaXNleFJZbHZra0lMeldYMXBxcFE9PSJ9 -----END ENCRYPTED COSIGN PRIVATE KEY----- ================================================ FILE: examples/keys/cosign.pub ================================================ -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOc6HkISHzVdUbtUsdjYtPuyPYBeg 4FCemyVurIM4KEORQk4OAu8ZNwxvGSoY3eAabYaFIPPQ8ROAjrbdPwNdJw== -----END PUBLIC KEY----- ================================================ FILE: examples/policies/allow-only-pods.yaml ================================================ # 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 # # https://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. apiVersion: policy.sigstore.dev/v1alpha1 kind: ClusterImagePolicy metadata: name: image-policy-typemeta-allow-only-pods spec: images: - glob: "ghcr.io/sigstore/timestamp-server**" authorities: - static: action: pass policy: includeTypeMeta: true type: "cue" data: | typemeta: kind: "Pod" ================================================ FILE: examples/policies/custom-key-attestation-sbom-spdxjson.yaml ================================================ # 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 # # https://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: custom-key-attestation-sbom-spdxjson # # Description: # Assert that all images must have a # signed SPDX SBOM (spdxjson) attestation # using a custom key # apiVersion: policy.sigstore.dev/v1alpha1 kind: ClusterImagePolicy metadata: name: custom-key-attestation-sbom-spdxjson spec: images: - glob: "**" authorities: - name: custom-key key: data: | -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEOc6HkISHzVdUbtUsdjYtPuyPYBeg 4FCemyVurIM4KEORQk4OAu8ZNwxvGSoY3eAabYaFIPPQ8ROAjrbdPwNdJw== -----END PUBLIC KEY----- ctlog: url: https://rekor.sigstore.dev attestations: - name: must-have-spdxjson predicateType: spdxjson policy: type: cue data: | predicateType: "https://spdx.dev/Document" ================================================ FILE: examples/policies/keyless-attestation-sbom-spdxjson.yaml ================================================ # 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 # # https://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: keyless-attestation-sbom-spdxjson # # Description: # Assert that all images must have a # "keyless" signed SPDX SBOM (spdxjson) # attestation against the public Fulcio root # apiVersion: policy.sigstore.dev/v1alpha1 kind: ClusterImagePolicy metadata: name: keyless-attestation-sbom-spdxjson spec: images: - glob: "**" authorities: - name: keyless keyless: url: "https://fulcio.sigstore.dev" identities: - issuer: https://token.actions.githubusercontent.com subject: "https://github.com/sigstore/policy-controller/.github/workflows/policy-tester-examples.yml@refs/heads/main" ctlog: url: https://rekor.sigstore.dev attestations: - name: must-have-spdxjson predicateType: spdxjson policy: type: cue data: | predicateType: "https://spdx.dev/Document" ================================================ FILE: examples/policies/release-signed-by-github-actions.yaml ================================================ # 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 # # https://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: release-signed-by-github-actions # # Description: # Assert that a policy-controller release was signed by expected subject # and issuer. # apiVersion: policy.sigstore.dev/v1alpha1 kind: ClusterImagePolicy metadata: name: image-is-signed-by-github-actions spec: images: # This is the release v0.3.0 - glob: "gcr.io/projectsigstore/policy-webhook@sha256:d1e7af59381793687db4673277005276eb73a06cf555503138dd18eaa1ca47d6" authorities: - keyless: # Signed by the public Fulcio certificate authority url: https://fulcio.sigstore.dev identities: # Matches the Github Actions OIDC issuer - issuer: https://token.actions.githubusercontent.com # Matches a specific github workflow on main branch. Here we use the # sigstore policy controller example testing workflow as an example. subject: "https://github.com/sigstore/policy-controller/.github/workflows/release.yaml@refs/tags/v0.3.0" ctlog: url: https://rekor.sigstore.dev ================================================ FILE: examples/policies/signed-by-aws-kms-key.yaml ================================================ # 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 # # https://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: image-is-signed-by-aws-kms-key # # Description: # Assert that images from are signed by a specific # AWS KMS key # apiVersion: policy.sigstore.dev/v1alpha1 kind: ClusterImagePolicy metadata: name: image-is-signed-by-aws-kms-key spec: images: # All images - glob: "**" authorities: - name: aws-kms key: # NB: the policy controller must have kms.DescribeKey, kms.GetPublicKey # and kms.Verify IAM permissions on the relevant key. kms: awskms:///arn:aws:kms:<< region >>:<< account id >>:key/<< key id >> ctlog: url: https://rekor.sigstore.dev ================================================ FILE: examples/policies/signed-by-gcp-kms-key.yaml ================================================ # 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 # # https://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: image-is-signed-by-gcp-kms-key # # Description: # Assert that images from are signed by a specific # GCP KMS key # apiVersion: policy.sigstore.dev/v1alpha1 kind: ClusterImagePolicy metadata: name: image-is-signed-by-gcp-kms-key spec: images: # All images - glob: "**" authorities: - name: gcp-kms key: kms: gcpkms://projects/${PROJECT_ID}/locations/${REGION}/keyRings/${KEY_RING}/cryptoKeys/${KEY_NAME}/cryptoKeyVersions/${KEY_VERSION} ctlog: url: https://rekor.sigstore.dev ================================================ FILE: examples/policies/signed-by-github-actions.yaml ================================================ # 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 # # https://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: image-is-signed-by-github-actions # # Description: # Assert that images are signed by a specific Github Actions # workflow on the main branch. # apiVersion: policy.sigstore.dev/v1alpha1 kind: ClusterImagePolicy metadata: name: image-is-signed-by-github-actions spec: images: # All images in example repository matched - glob: "**" authorities: - keyless: # Signed by the public Fulcio certificate authority url: https://fulcio.sigstore.dev identities: # Matches the Github Actions OIDC issuer - issuer: https://token.actions.githubusercontent.com # Matches a specific github workflow on main branch. Here we use the # sigstore policy controller example testing workflow as an example. subject: "https://github.com/sigstore/policy-controller/.github/workflows/policy-tester-examples.yml@refs/heads/main" ctlog: url: https://rekor.sigstore.dev ================================================ FILE: examples/sboms/example.spdx.json ================================================ { "spdxVersion": "SPDX-2.2", "dataLicense": "CC0-1.0", "SPDXID": "SPDXRef-DOCUMENT", "creationInfo": { "created": "2020-11-24T01:12:27Z", "creators": [ { "Person": "Nisha K (nishak@vmware.com)" } ] }, "name": "golang-dist", "documentNamespace": "https://swinslow.net/spdx-examples/example7/golang-dist", "documentDescribes": [ "SPDXRef-golang-dist" ], "packages": [ { "packageName": "go1.16.4.linux-amd64", "SPDXID": "SPDXRef-golang-dist", "downloadLocation": "https://golang.org/dl/go1.16.4.linux-amd64.tar.gz", "packageVersion": "1.16.4", "filesAnalyzed": "false", "checksums": [ { "algorithm": "SHA256", "checksumValue": "7154e88f5a8047aad4b80ebace58a059e36e7e2e4eb3b383127a28c711b4ff59" } ], "packageLicenseConcluded": "NOASSERTION", "packageLicenseDeclared": "LicenseRef-Golang-BSD-plus-Patents", "packageCopyrightText": "Copyright (c) 2009 The Go Authors. All rights reserved." }, { "packageName": "go", "SPDXID": "SPDXRef-go-compiler", "downloadLocation": "https://golang.org/dl/go1.16.4.linux-amd64.tar.gz", "packageVersion": "1.16.4", "filesAnalyzed": "false", "packageLicenseConcluded": "NOASSERTION", "packageLicenseDeclared": "NOASSERTION", "packageCopyrightText": "NOASSERTION" } ] } ================================================ FILE: go.mod ================================================ module github.com/sigstore/policy-controller go 1.25.7 require ( github.com/aws/aws-sdk-go-v2 v1.41.2 github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/go-cmp v0.7.0 github.com/google/go-containerregistry v0.21.3 github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20260317232201-3888fb8f8738 github.com/google/go-containerregistry/pkg/authn/kubernetes v0.0.0-20260317232201-3888fb8f8738 github.com/hashicorp/errwrap v1.1.0 github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-retryablehttp v0.7.8 github.com/hashicorp/go-rootcerts v1.0.2 github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 github.com/hashicorp/go-sockaddr v1.0.7 github.com/hashicorp/golang-lru v1.0.2 github.com/hashicorp/hcl v1.0.1-vault-7 github.com/kelseyhightower/envconfig v1.4.0 github.com/letsencrypt/boulder v0.20251110.0 github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c github.com/ryanuber/go-glob v1.0.0 github.com/sigstore/cosign/v3 v3.0.5 github.com/sigstore/rekor v1.5.0 github.com/sigstore/sigstore v1.10.4 github.com/stretchr/testify v1.11.1 github.com/theupdateframework/go-tuf v0.7.0 github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 go.uber.org/zap v1.27.1 golang.org/x/crypto v0.49.0 golang.org/x/net v0.52.0 golang.org/x/sys v0.42.0 // indirect golang.org/x/time v0.14.0 google.golang.org/grpc v1.79.3 google.golang.org/protobuf v1.36.11 gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/api v0.35.2 k8s.io/apimachinery v0.35.2 k8s.io/client-go v0.35.2 k8s.io/code-generator v0.32.2 k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 knative.dev/hack v0.0.0-20240111013919-e89096d74d85 sigs.k8s.io/release-utils v0.12.3 sigs.k8s.io/yaml v1.6.0 ) require github.com/spf13/cobra v1.10.2 require ( github.com/Azure/azure-sdk-for-go v68.0.0+incompatible github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.12.0 github.com/cenkalti/backoff/v4 v4.3.0 github.com/docker/docker v28.5.2+incompatible github.com/docker/docker-credential-helpers v0.9.5 github.com/docker/go-connections v0.6.0 github.com/go-jose/go-jose/v4 v4.1.3 github.com/hashicorp/vault/api v1.22.0 github.com/natefinch/atomic v1.0.1 github.com/sigstore/protobuf-specs v0.5.0 github.com/sigstore/scaffolding v0.7.22 github.com/sigstore/sigstore-go v1.1.4 github.com/sigstore/sigstore/pkg/signature/kms/aws v1.10.4 github.com/sigstore/sigstore/pkg/signature/kms/azure v1.10.4 github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.10.4 github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.10.4 github.com/spf13/viper v1.21.0 github.com/theupdateframework/go-tuf/v2 v2.4.1 knative.dev/hack/schema v0.0.0-20240607132042-09143140a254 knative.dev/pkg v0.0.0-20230612155445-74c4be5e935e ) require ( cloud.google.com/go v0.123.0 // indirect cloud.google.com/go/auth v0.18.1 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.9.0 // indirect cloud.google.com/go/iam v1.5.3 // indirect cloud.google.com/go/kms v1.25.0 // indirect cloud.google.com/go/longrunning v0.8.0 // indirect contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d // indirect contrib.go.opencensus.io/exporter/prometheus v0.4.2 // indirect cuelang.org/go v0.15.4 // indirect github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/provider v0.14.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.4.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect github.com/Azure/go-autorest/autorest v0.11.30 // indirect github.com/Azure/go-autorest/autorest/adal v0.9.24 // indirect github.com/Azure/go-autorest/autorest/azure/auth v0.5.13 // indirect github.com/Azure/go-autorest/autorest/azure/cli v0.4.7 // indirect github.com/Azure/go-autorest/autorest/date v0.3.1 // indirect github.com/Azure/go-autorest/logger v0.2.2 // indirect github.com/Azure/go-autorest/tracing v0.6.1 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/ThalesIgnite/crypto11 v1.2.5 // indirect github.com/agnivade/levenshtein v1.2.1 // indirect github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 // indirect github.com/alibabacloud-go/cr-20160607 v1.0.1 // indirect github.com/alibabacloud-go/cr-20181201 v1.0.10 // indirect github.com/alibabacloud-go/darabonba-openapi v0.2.1 // indirect github.com/alibabacloud-go/debug v1.0.0 // indirect github.com/alibabacloud-go/endpoint-util v1.1.1 // indirect github.com/alibabacloud-go/openapi-util v0.1.0 // indirect github.com/alibabacloud-go/tea v1.2.1 // indirect github.com/alibabacloud-go/tea-utils v1.4.5 // indirect github.com/alibabacloud-go/tea-xml v1.1.3 // indirect github.com/aliyun/credentials-go v1.3.2 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go-v2/config v1.32.10 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.19.10 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.18 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.18 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.18 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect github.com/aws/aws-sdk-go-v2/service/ecr v1.55.3 // indirect github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.10 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.5 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.18 // indirect github.com/aws/aws-sdk-go-v2/service/kms v1.49.5 // indirect github.com/aws/aws-sdk-go-v2/service/signin v1.0.6 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.30.11 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.15 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.41.7 // indirect github.com/aws/smithy-go v1.24.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver v3.5.1+incompatible // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/blendle/zapdriver v1.3.1 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect github.com/clbanning/mxj/v2 v2.7.0 // indirect github.com/cockroachdb/apd/v3 v3.2.1 // indirect github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/stargz-snapshotter/estargz v0.18.2 // indirect github.com/coreos/go-oidc/v3 v3.17.0 // indirect github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect github.com/dimchansky/utfbom v1.1.1 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/docker/cli v29.3.0+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/go-units v0.5.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/emicklei/proto v1.14.2 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.7.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/go-chi/chi/v5 v5.2.4 // indirect github.com/go-ini/ini v1.67.0 // indirect github.com/go-kit/log v0.2.1 // indirect github.com/go-logfmt/logfmt v0.5.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.24.1 // indirect github.com/go-openapi/errors v0.22.6 // indirect github.com/go-openapi/jsonpointer v0.22.4 // indirect github.com/go-openapi/jsonreference v0.21.4 // indirect github.com/go-openapi/loads v0.23.2 // indirect github.com/go-openapi/runtime v0.29.2 // indirect github.com/go-openapi/spec v0.22.3 // indirect github.com/go-openapi/strfmt v0.25.0 // indirect github.com/go-openapi/swag v0.25.4 // indirect github.com/go-openapi/swag/cmdutils v0.25.4 // indirect github.com/go-openapi/swag/conv v0.25.4 // indirect github.com/go-openapi/swag/fileutils v0.25.4 // indirect github.com/go-openapi/swag/jsonname v0.25.4 // indirect github.com/go-openapi/swag/jsonutils v0.25.4 // indirect github.com/go-openapi/swag/loading v0.25.4 // indirect github.com/go-openapi/swag/mangling v0.25.4 // indirect github.com/go-openapi/swag/netutils v0.25.4 // indirect github.com/go-openapi/swag/stringutils v0.25.4 // indirect github.com/go-openapi/swag/typeutils v0.25.4 // indirect github.com/go-openapi/swag/yamlutils v0.25.4 // indirect github.com/go-openapi/validate v0.25.1 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobuffalo/flect v1.0.2 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-jwt/jwt/v4 v4.5.2 // indirect github.com/golang-jwt/jwt/v5 v5.3.0 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/google/certificate-transparency-go v1.3.2 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-github/v73 v73.0.0 // indirect github.com/google/go-querystring v1.2.0 // indirect github.com/google/s2a-go v0.1.9 // indirect github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.11 // indirect github.com/googleapis/gax-go/v2 v2.17.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.5 // indirect github.com/in-toto/attestation v1.1.2 // indirect github.com/in-toto/in-toto-golang v0.9.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 // indirect github.com/jellydator/ttlcache/v3 v3.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.4 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/lestrrat-go/blackmagic v1.0.4 // indirect github.com/lestrrat-go/dsig v1.0.0 // indirect github.com/lestrrat-go/dsig-secp256k1 v1.0.0 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect github.com/lestrrat-go/httprc/v3 v3.0.1 // indirect github.com/lestrrat-go/jwx/v3 v3.0.12 // indirect github.com/lestrrat-go/option v1.0.1 // indirect github.com/lestrrat-go/option/v2 v2.0.0 // indirect github.com/miekg/pkcs11 v1.1.2 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/sys/atomicwriter v0.1.0 // indirect github.com/moby/term v0.5.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/morikuni/aec v1.1.0 // indirect github.com/mozillazg/docker-credential-acr-helper v0.4.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/open-policy-agent/opa v1.12.3 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.5 // indirect github.com/prometheus/procfs v0.19.2 // indirect github.com/prometheus/statsd_exporter v0.22.8 // indirect github.com/protocolbuffers/txtpbfmt v0.0.0-20251016062345-16587c79cd91 // indirect github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sassoftware/relic v7.2.1+incompatible // indirect github.com/secure-systems-lab/go-securesystemslib v0.10.0 // indirect github.com/segmentio/asm v1.2.1 // indirect github.com/shibumi/go-pathspec v1.3.0 // indirect github.com/sigstore/rekor-tiles/v2 v2.2.0 // indirect github.com/sigstore/timestamp-authority/v2 v2.0.4 // indirect github.com/sirupsen/logrus v1.9.4 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tchap/go-patricia/v2 v2.3.3 // indirect github.com/thales-e-security/pool v0.0.2 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect github.com/transparency-dev/formats v0.0.0-20251017110053-404c0d5b696c // indirect github.com/transparency-dev/merkle v0.0.2 // indirect github.com/valyala/fastjson v1.6.4 // indirect github.com/vbatts/tar-split v0.12.2 // indirect github.com/vektah/gqlparser/v2 v2.5.31 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/yashtewari/glob-intersection v0.2.0 // indirect gitlab.com/gitlab-org/api/client-go v1.25.0 // indirect go.mongodb.org/mongo-driver v1.17.6 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect go.opentelemetry.io/otel v1.42.0 // indirect go.opentelemetry.io/otel/metric v1.42.0 // indirect go.opentelemetry.io/otel/sdk v1.42.0 // indirect go.opentelemetry.io/otel/trace v1.42.0 // indirect go.uber.org/atomic v1.9.0 // indirect go.uber.org/automaxprocs v1.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/mod v0.34.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/sync v0.20.0 // indirect golang.org/x/term v0.41.0 // indirect golang.org/x/text v0.35.0 // indirect golang.org/x/tools v0.43.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/api v0.267.0 // indirect google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect k8s.io/apiextensions-apiserver v0.27.6 // indirect k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01 // indirect k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect ) // TODO: this dependency causes issues on webhook startup due // to conflicting "log_dir" flags between this and klog (knative) replace github.com/golang/glog => github.com/jdolitsky/glog v0.0.0-20220729172235-78744e90d087 // knative deps require to use an old k8s.io/gengo so we need to replace these ones replace k8s.io/code-generator => k8s.io/code-generator v0.29.4 ================================================ FILE: go.sum ================================================ al.essio.dev/pkg/shellescape v1.6.0 h1:NxFcEqzFSEVCGN2yq7Huv/9hyCEGVa/TncnOOBBeXHA= al.essio.dev/pkg/shellescape v1.6.0/go.mod h1:6sIqp7X2P6mThCQ7twERpZTuigpr6KbZWtls1U8I890= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= cloud.google.com/go/auth v0.18.1 h1:IwTEx92GFUo2pJ6Qea0EU3zYvKnTAeRCODxfA/G5UWs= cloud.google.com/go/auth v0.18.1/go.mod h1:GfTYoS9G3CWpRA3Va9doKN9mjPGRS+v41jmZAhBzbrA= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/iam v1.5.3 h1:+vMINPiDF2ognBJ97ABAYYwRgsaqxPbQDlMnbHMjolc= cloud.google.com/go/iam v1.5.3/go.mod h1:MR3v9oLkZCTlaqljW6Eb2d3HGDGK5/bDv93jhfISFvU= cloud.google.com/go/kms v1.25.0 h1:gVqvGGUmz0nYCmtoxWmdc1wli2L1apgP8U4fghPGSbQ= cloud.google.com/go/kms v1.25.0/go.mod h1:XIdHkzfj0bUO3E+LvwPg+oc7s58/Ns8Nd8Sdtljihbk= cloud.google.com/go/longrunning v0.8.0 h1:LiKK77J3bx5gDLi4SMViHixjD2ohlkwBi+mKA7EhfW8= cloud.google.com/go/longrunning v0.8.0/go.mod h1:UmErU2Onzi+fKDg2gR7dusz11Pe26aknR4kHmJJqIfk= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d h1:LblfooH1lKOpp1hIhukktmSAxFkqMPFk9KR6iZ0MJNI= contrib.go.opencensus.io/exporter/ocagent v0.7.1-0.20200907061046-05415f1de66d/go.mod h1:IshRmMJBhDfFj5Y67nVhMYTTIze91RUeT73ipWKs/GY= contrib.go.opencensus.io/exporter/prometheus v0.4.2 h1:sqfsYl5GIY/L570iT+l93ehxaWJs2/OwXtiWwew3oAg= contrib.go.opencensus.io/exporter/prometheus v0.4.2/go.mod h1:dvEHbiKmgvbr5pjaF9fpw1KeYcjrnC1J8B+JKjsZyRQ= cuelabs.dev/go/oci/ociregistry v0.0.0-20250722084951-074d06050084 h1:4k1yAtPvZJZQTu8DRY8muBo0LHv6TqtrE0AO5n6IPYs= cuelabs.dev/go/oci/ociregistry v0.0.0-20250722084951-074d06050084/go.mod h1:4WWeZNxUO1vRoZWAHIG0KZOd6dA25ypyWuwD3ti0Tdc= cuelang.org/go v0.15.4 h1:lrkTDhqy8dveHgX1ZLQ6WmgbhD8+rXa0fD25hxEKYhw= cuelang.org/go v0.15.4/go.mod h1:NYw6n4akZcTjA7QQwJ1/gqWrrhsN4aZwhcAL0jv9rZE= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.1 h1:YpjwWWlNmGIDyXOn8zLzqiD+9TyIlPhGFG96P39uBpw= filippo.io/edwards25519 v1.1.1/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d h1:zjqpY4C7H15HjRPEenkS4SAn3Jy2eRRjkjZbGR30TOg= github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d/go.mod h1:XNqJ7hv2kY++g8XEHREpi+JqZo3+0l+CH2egBVN4yqM= github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/provider v0.14.0 h1:kcnfY4vljxXliXDBrA9K9lwF8IoEZ4Up6Eg9kWTIm28= github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/provider v0.14.0/go.mod h1:tlqp9mUGbsP+0z3Q+c0Q5MgSdq/OMwQhm5bffR3Q3ss= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 h1:fou+2+WFTib47nS+nz/ozhEBnvU96bKHy6LjRsY4E28= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0/go.mod h1:t76Ruy8AHvUAC8GfMWJMa0ElSbuIcO03NLpynfbgsPA= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1/go.mod h1:IYus9qsFobWIc2YVwe/WPjcnyCkPKtnHAqUYeebc8z0= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY= github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2/go.mod h1:Pa9ZNPuoNu/GztvBSKk9J1cDJW6vk/n0zLtV4mgd8N8= github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2 h1:9iefClla7iYpfYWdzPCRDozdmndjTm8DXdpCzPajMgA= github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2/go.mod h1:XtLgD3ZD34DAaVIIAyG3objl5DynM3CQ/vMcbBNJZGI= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.4.0 h1:E4MgwLBGeVB5f2MdcIVD3ELVAWpr+WD6MUe1i+tM/PA= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.4.0/go.mod h1:Y2b/1clN4zsAoUd/pgNAQHjLDnTis/6ROkUfyob6psM= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 h1:nCYfgcSyHZXJI8J0IWE5MsCGlb2xp9fJiXyxWgmOFg4= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0/go.mod h1:ucUjca2JtSZboY8IoUqyQyuuXvwbMBVwFOm0vdQPNhA= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs= github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= github.com/Azure/go-autorest/autorest v0.11.28/go.mod h1:MrkzG3Y3AH668QyF9KRk5neJnGgmhQ6krbhR8Q5eMvA= github.com/Azure/go-autorest/autorest v0.11.30 h1:iaZ1RGz/ALZtN5eq4Nr1SOFSlf2E4pDI3Tcsl+dZPVE= github.com/Azure/go-autorest/autorest v0.11.30/go.mod h1:t1kpPIOpIVX7annvothKvb0stsrXa37i7b+xpmBW8Fs= github.com/Azure/go-autorest/autorest/adal v0.9.18/go.mod h1:XVVeme+LZwABT8K5Lc3hA4nAe8LDBVle26gTrguhhPQ= github.com/Azure/go-autorest/autorest/adal v0.9.22/go.mod h1:XuAbAEUv2Tta//+voMI038TrJBqjKam0me7qR+L8Cmk= github.com/Azure/go-autorest/autorest/adal v0.9.24 h1:BHZfgGsGwdkHDyZdtQRQk1WeUdW0m2WPAwuHZwUi5i4= github.com/Azure/go-autorest/autorest/adal v0.9.24/go.mod h1:7T1+g0PYFmACYW5LlG2fcoPiPlFHjClyRGL7dRlP5c8= github.com/Azure/go-autorest/autorest/azure/auth v0.5.13 h1:Ov8avRZi2vmrE2JcXw+tu5K/yB41r7xK9GZDiBF7NdM= github.com/Azure/go-autorest/autorest/azure/auth v0.5.13/go.mod h1:5BAVfWLWXihP47vYrPuBKKf4cS0bXI+KM9Qx6ETDJYo= github.com/Azure/go-autorest/autorest/azure/cli v0.4.6/go.mod h1:piCfgPho7BiIDdEQ1+g4VmKyD5y+p/XtSNqE6Hc4QD0= github.com/Azure/go-autorest/autorest/azure/cli v0.4.7 h1:Q9R3utmFg9K1B4OYtAZ7ZUUvIUdzQt7G2MN5Hi/d670= github.com/Azure/go-autorest/autorest/azure/cli v0.4.7/go.mod h1:bVrAueELJ0CKLBpUHDIvD516TwmHmzqwCpvONWRsw3s= github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= github.com/Azure/go-autorest/autorest/date v0.3.1 h1:o9Z8Jyt+VJJTCZ/UORishuHOusBwolhjokt9s5k8I4w= github.com/Azure/go-autorest/autorest/date v0.3.1/go.mod h1:Dz/RDmXlfiFFS/eW+b/xMUSFs1tboPVy6UjgADToWDM= github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= github.com/Azure/go-autorest/autorest/mocks v0.4.2 h1:PGN4EDXnuQbojHbU0UWoNvmu9AGVwYHG9/fkDYhtAfw= github.com/Azure/go-autorest/autorest/mocks v0.4.2/go.mod h1:Vy7OitM9Kei0i1Oj+LvyAWMXJHeKH1MVlzFugfVrmyU= github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/logger v0.2.2 h1:hYqBsEBywrrOSW24kkOCXRcKfKhK76OzLTfF+MYDE2o= github.com/Azure/go-autorest/logger v0.2.2/go.mod h1:I5fg9K52o+iuydlWfa9T5K6WFos9XYr9dYTFzpqgibw= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/Azure/go-autorest/tracing v0.6.1 h1:YUMSrC/CeD1ZnnXcNYU4a/fzsO35u2Fsful9L/2nyR0= github.com/Azure/go-autorest/tracing v0.6.1/go.mod h1:/3EgjbsjraOqiicERAeu3m7/z0x1TzjQGAwDrJrXGkc= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs= github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/ThalesIgnite/crypto11 v1.2.5 h1:1IiIIEqYmBvUYFeMnHqRft4bwf/O36jryEUpY+9ef8E= github.com/ThalesIgnite/crypto11 v1.2.5/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR2E23+wTQe/MlE= github.com/agnivade/levenshtein v1.2.1 h1:EHBY3UOn1gwdy/VbFwgo4cxecRznFk7fKWN1KOX7eoM= github.com/agnivade/levenshtein v1.2.1/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.2/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 h1:iC9YFYKDGEy3n/FtqJnOkZsene9olVspKmkX5A2YBEo= github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= github.com/alibabacloud-go/cr-20160607 v1.0.1 h1:WEnP1iPFKJU74ryUKh/YDPHoxMZawqlPajOymyNAkts= github.com/alibabacloud-go/cr-20160607 v1.0.1/go.mod h1:QHeKZtZ3F3FOE+/uIXCBAp8POwnUYekpLwr1dtQa5r0= github.com/alibabacloud-go/cr-20181201 v1.0.10 h1:B60f6S1imsgn2fgC6X6FrVNrONDrbCT0NwYhsJ0C9/c= github.com/alibabacloud-go/cr-20181201 v1.0.10/go.mod h1:VN9orB/w5G20FjytoSpZROqu9ZqxwycASmGqYUJSoDc= github.com/alibabacloud-go/darabonba-openapi v0.1.12/go.mod h1:sTAjsFJmVsmcVeklL9d9uDBlFsgl43wZ6jhI6BHqHqU= github.com/alibabacloud-go/darabonba-openapi v0.1.14/go.mod h1:w4CosR7O/kapCtEEMBm3JsQqWBU/CnZ2o0pHorsTWDI= github.com/alibabacloud-go/darabonba-openapi v0.2.1 h1:WyzxxKvhdVDlwpAMOHgAiCJ+NXa6g5ZWPFEzaK/ewwY= github.com/alibabacloud-go/darabonba-openapi v0.2.1/go.mod h1:zXOqLbpIqq543oioL9IuuZYOQgHQ5B8/n5OPrnko8aY= github.com/alibabacloud-go/darabonba-string v1.0.0/go.mod h1:93cTfV3vuPhhEwGGpKKqhVW4jLe7tDpo3LUM0i0g6mA= github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY= github.com/alibabacloud-go/debug v1.0.0 h1:3eIEQWfay1fB24PQIEzXAswlVJtdQok8f3EVN5VrBnA= github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc= github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= github.com/alibabacloud-go/endpoint-util v1.1.1 h1:ZkBv2/jnghxtU0p+upSU0GGzW1VL9GQdZO3mcSUTUy8= github.com/alibabacloud-go/endpoint-util v1.1.1/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= github.com/alibabacloud-go/openapi-util v0.0.9/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= github.com/alibabacloud-go/openapi-util v0.0.10/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= github.com/alibabacloud-go/openapi-util v0.0.11/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= github.com/alibabacloud-go/openapi-util v0.1.0 h1:0z75cIULkDrdEhkLWgi9tnLe+KhAFE/r5Pb3312/eAY= github.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg= github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= github.com/alibabacloud-go/tea v1.1.11/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= github.com/alibabacloud-go/tea v1.1.19/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= github.com/alibabacloud-go/tea v1.2.1 h1:rFF1LnrAdhaiPmKwH5xwYOKlMh66CqRwPUTzIK74ask= github.com/alibabacloud-go/tea v1.2.1/go.mod h1:qbzof29bM/IFhLMtJPrgTGK3eauV5J2wSyEUo4OEmnA= github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= github.com/alibabacloud-go/tea-utils v1.3.9/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= github.com/alibabacloud-go/tea-utils v1.4.3/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw= github.com/alibabacloud-go/tea-utils v1.4.5 h1:h0/6Xd2f3bPE4XHTvkpjwxowIwRCJAJOqY6Eq8f3zfA= github.com/alibabacloud-go/tea-utils v1.4.5/go.mod h1:KNcT0oXlZZxOXINnZBs6YvgOd5aYp9U67G+E3R8fcQw= github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0= github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= github.com/aliyun/credentials-go v1.3.2 h1:L4WppI9rctC8PdlMgyTkF8bBsy9pyKQEzBD1bHMRl+g= github.com/aliyun/credentials-go v1.3.2/go.mod h1:tlpz4uys4Rn7Ik4/piGRrTbXy2uLKvePgQJJduE+Y5c= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.55.8 h1:JRmEUbU52aJQZ2AjX4q4Wu7t4uZjOu71uyNmaWlUkJQ= github.com/aws/aws-sdk-go v1.55.8/go.mod h1:ZkViS9AqA6otK+JBBNH2++sx1sgxrPKcSzPPvQkUtXk= github.com/aws/aws-sdk-go-v2 v1.41.2 h1:LuT2rzqNQsauaGkPK/7813XxcZ3o3yePY0Iy891T2ls= github.com/aws/aws-sdk-go-v2 v1.41.2/go.mod h1:IvvlAZQXvTXznUPfRVfryiG1fbzE2NGK6m9u39YQ+S4= github.com/aws/aws-sdk-go-v2/config v1.32.10 h1:9DMthfO6XWZYLfzZglAgW5Fyou2nRI5CuV44sTedKBI= github.com/aws/aws-sdk-go-v2/config v1.32.10/go.mod h1:2rUIOnA2JaiqYmSKYmRJlcMWy6qTj1vuRFscppSBMcw= github.com/aws/aws-sdk-go-v2/credentials v1.19.10 h1:EEhmEUFCE1Yhl7vDhNOI5OCL/iKMdkkYFTRpZXNw7m8= github.com/aws/aws-sdk-go-v2/credentials v1.19.10/go.mod h1:RnnlFCAlxQCkN2Q379B67USkBMu1PipEEiibzYN5UTE= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.18 h1:Ii4s+Sq3yDfaMLpjrJsqD6SmG/Wq/P5L/hw2qa78UAY= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.18/go.mod h1:6x81qnY++ovptLE6nWQeWrpXxbnlIex+4H4eYYGcqfc= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.18 h1:F43zk1vemYIqPAwhjTjYIz0irU2EY7sOb/F5eJ3HuyM= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.18/go.mod h1:w1jdlZXrGKaJcNoL+Nnrj+k5wlpGXqnNrKoP22HvAug= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.18 h1:xCeWVjj0ki0l3nruoyP2slHsGArMxeiiaoPN5QZH6YQ= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.18/go.mod h1:r/eLGuGCBw6l36ZRWiw6PaZwPXb6YOj+i/7MizNl5/k= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc= github.com/aws/aws-sdk-go-v2/service/ecr v1.55.3 h1:RtGctYMmkTerGClvdY6bHXdtly4FeYw9wz/NPz62LF8= github.com/aws/aws-sdk-go-v2/service/ecr v1.55.3/go.mod h1:vBfBu24Ka3/5UZtepbTV0gnc9VPLT8ok+0oDDaYAzn4= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.10 h1:1A/sI3LNMi3fhRI5TFLMwwo7ALAALSFVCSGvFlr1Iys= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.38.10/go.mod h1:Diyyyz0b43X13pdi1mVMqlTwDjOmRbJMvDsqnduUYWM= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.5 h1:CeY9LUdur+Dxoeldqoun6y4WtJ3RQtzk0JMP2gfUay0= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.5/go.mod h1:AZLZf2fMaahW5s/wMRciu1sYbdsikT/UHwbUjOdEVTc= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.18 h1:LTRCYFlnnKFlKsyIQxKhJuDuA3ZkrDQMRYm6rXiHlLY= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.18/go.mod h1:XhwkgGG6bHSd00nO/mexWTcTjgd6PjuvWQMqSn2UaEk= github.com/aws/aws-sdk-go-v2/service/kms v1.49.5 h1:DKibav4XF66XSeaXcrn9GlWGHos6D/vJ4r7jsK7z5CE= github.com/aws/aws-sdk-go-v2/service/kms v1.49.5/go.mod h1:1SdcmEGUEQE1mrU2sIgeHtcMSxHuybhPvuEPANzIDfI= github.com/aws/aws-sdk-go-v2/service/signin v1.0.6 h1:MzORe+J94I+hYu2a6XmV5yC9huoTv8NRcCrUNedDypQ= github.com/aws/aws-sdk-go-v2/service/signin v1.0.6/go.mod h1:hXzcHLARD7GeWnifd8j9RWqtfIgxj4/cAtIVIK7hg8g= github.com/aws/aws-sdk-go-v2/service/sso v1.30.11 h1:7oGD8KPfBOJGXiCoRKrrrQkbvCp8N++u36hrLMPey6o= github.com/aws/aws-sdk-go-v2/service/sso v1.30.11/go.mod h1:0DO9B5EUJQlIDif+XJRWCljZRKsAFKh3gpFz7UnDtOo= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.15 h1:edCcNp9eGIUDUCrzoCu1jWAXLGFIizeqkdkKgRlJwWc= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.15/go.mod h1:lyRQKED9xWfgkYC/wmmYfv7iVIM68Z5OQ88ZdcV1QbU= github.com/aws/aws-sdk-go-v2/service/sts v1.41.7 h1:NITQpgo9A5NrDZ57uOWj+abvXSb83BbyggcUBVksN7c= github.com/aws/aws-sdk-go-v2/service/sts v1.41.7/go.mod h1:sks5UWBhEuWYDPdwlnRFn1w7xWdH29Jcpe+/PJQefEs= github.com/aws/smithy-go v1.24.1 h1:VbyeNfmYkWoxMVpGUAbQumkODcYmfMRfZ8yQiH30SK0= github.com/aws/smithy-go v1.24.1/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.12.0 h1:JFWXO6QPihCknDdnL6VaQE57km4ZKheHIGd9YiOGcTo= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.12.0/go.mod h1:046/oLyFlYdAghYQE2yHXi/E//VM5Cf3/dFmA+3CZ0c= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE= github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc= github.com/bytecodealliance/wasmtime-go/v39 v39.0.1 h1:RibaT47yiyCRxMOj/l2cvL8cWiWBSqDXHyqsa9sGcCE= github.com/bytecodealliance/wasmtime-go/v39 v39.0.1/go.mod h1:miR4NYIEBXeDNamZIzpskhJ0z/p8al+lwMWylQ/ZJb4= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g= github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 h1:krfRl01rzPzxSxyLyrChD+U+MzsBXbm0OwYYB67uF+4= github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589/go.mod h1:OuDyvmLnMCwa2ep4Jkm6nyA0ocJuZlGyk2gGseVzERM= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 h1:6xNmx7iTtyBRev0+D/Tv1FZd4SCg8axKApyNyRsAt/w= github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI= github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg= github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUoc7Ik9EfrFqcylYqgPZ9ANSbTAntnE= github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4= github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ= github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= github.com/containerd/stargz-snapshotter/estargz v0.18.2 h1:yXkZFYIzz3eoLwlTUZKz2iQ4MrckBxJjkmD16ynUTrw= github.com/containerd/stargz-snapshotter/estargz v0.18.2/go.mod h1:XyVU5tcJ3PRpkA9XS2T5us6Eg35yM0214Y+wvrZTBrY= github.com/coreos/go-oidc/v3 v3.17.0 h1:hWBGaQfbi0iVviX4ibC7bk8OKT5qNr4klBaCHVNvehc= github.com/coreos/go-oidc/v3 v3.17.0/go.mod h1:wqPbKFrVnE90vty060SB40FCJ8fTHTxSwyXJqZH+sI8= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 h1:uX1JmpONuD549D73r6cgnxyUu18Zb7yHAy5AYU0Pm4Q= github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw= github.com/danieljoos/wincred v1.2.3 h1:v7dZC2x32Ut3nEfRH+vhoZGvN72+dQ/snVXo/vMFLdQ= github.com/danieljoos/wincred v1.2.3/go.mod h1:6qqX0WNrS4RzPZ1tnroDzq9kY3fu1KwE7MRLQK4X0bs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40= github.com/dgraph-io/badger/v4 v4.8.0 h1:JYph1ChBijCw8SLeybvPINizbDKWZ5n/GYbz2yhN/bs= github.com/dgraph-io/badger/v4 v4.8.0/go.mod h1:U6on6e8k/RTbUWxqKR0MvugJuVmkxSNc79ap4917h4w= github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINAEJdWGOM= github.com/dgraph-io/ristretto/v2 v2.2.0/go.mod h1:RZrm63UmcBAaYWC1DotLYBmTvgkrs0+XhBd7Npn7/zI= github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54 h1:SG7nF6SRlWhcT7cNTs5R6Hk4V2lcmLz2NsG2VnInyNo= github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/digitorus/pkcs7 v0.0.0-20230713084857-e76b763bdc49/go.mod h1:SKVExuS+vpu2l9IoOc0RwqE7NYnb0JlcFHFnEJkVDzc= github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 h1:ge14PCmCvPjpMQMIAH7uKg0lrtNSOdpYsRXlwk3QbaE= github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352/go.mod h1:SKVExuS+vpu2l9IoOc0RwqE7NYnb0JlcFHFnEJkVDzc= github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 h1:lxmTCgmHE1GUYL7P0MlNa00M67axePTq+9nBSGddR8I= github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7/go.mod h1:GvWntX9qiTlOud0WkQ6ewFm0LPy5JUR1Xo0Ngbd1w6Y= github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/docker/cli v29.3.0+incompatible h1:z3iWveU7h19Pqx7alZES8j+IeFQZ1lhTwb2F+V9SVvk= github.com/docker/cli v29.3.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.9.5 h1:EFNN8DHvaiK8zVqFA2DT6BjXE0GzfLOZ38ggPTKePkY= github.com/docker/docker-credential-helpers v0.9.5/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c= github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/emicklei/go-restful/v3 v3.13.0 h1:C4Bl2xDndpU6nJ4bc1jXd+uTmYPVUwkD6bFY/oTyCes= github.com/emicklei/go-restful/v3 v3.13.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emicklei/proto v1.14.2 h1:wJPxPy2Xifja9cEMrcA/g08art5+7CGJNFNk35iXC1I= github.com/emicklei/proto v1.14.2/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA= github.com/envoyproxy/go-control-plane/envoy v1.36.0 h1:yg/JjO5E7ubRyKX3m07GF3reDNEnfOboJ0QySbH736g= github.com/envoyproxy/go-control-plane/envoy v1.36.0/go.mod h1:ty89S1YCCVruQAm9OtKeEkQLTb+Lkz0k8v9W0Oxsv98= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v1.3.0 h1:TvGH1wof4H33rezVKWSpqKz5NXWg5VPuZ0uONDT6eb4= github.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9zHIH36nmrm7oCbo4YKoSWA= github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.7.0 h1:nJqP7uwL84RJInrohHfW0Fx3awjbm8qZeFv0nW9SYGc= github.com/evanphx/json-patch/v5 v5.7.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI= github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-chi/chi/v5 v5.2.4 h1:WtFKPHwlywe8Srng8j2BhOD9312j9cGUxG1SP4V2cR4= github.com/go-chi/chi/v5 v5.2.4/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logfmt/logfmt v0.5.1 h1:otpy5pqBCBZ1ng9RQ0dPu4PN7ba75Y/aA+UpowDyNVA= github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/analysis v0.24.1 h1:Xp+7Yn/KOnVWYG8d+hPksOYnCYImE3TieBa7rBOesYM= github.com/go-openapi/analysis v0.24.1/go.mod h1:dU+qxX7QGU1rl7IYhBC8bIfmWQdX4Buoea4TGtxXY84= github.com/go-openapi/errors v0.22.6 h1:eDxcf89O8odEnohIXwEjY1IB4ph5vmbUsBMsFNwXWPo= github.com/go-openapi/errors v0.22.6/go.mod h1:z9S8ASTUqx7+CP1Q8dD8ewGH/1JWFFLX/2PmAYNQLgk= github.com/go-openapi/jsonpointer v0.22.4 h1:dZtK82WlNpVLDW2jlA1YCiVJFVqkED1MegOUy9kR5T4= github.com/go-openapi/jsonpointer v0.22.4/go.mod h1:elX9+UgznpFhgBuaMQ7iu4lvvX1nvNsesQ3oxmYTw80= github.com/go-openapi/jsonreference v0.21.4 h1:24qaE2y9bx/q3uRK/qN+TDwbok1NhbSmGjjySRCHtC8= github.com/go-openapi/jsonreference v0.21.4/go.mod h1:rIENPTjDbLpzQmQWCj5kKj3ZlmEh+EFVbz3RTUh30/4= github.com/go-openapi/loads v0.23.2 h1:rJXAcP7g1+lWyBHC7iTY+WAF0rprtM+pm8Jxv1uQJp4= github.com/go-openapi/loads v0.23.2/go.mod h1:IEVw1GfRt/P2Pplkelxzj9BYFajiWOtY2nHZNj4UnWY= github.com/go-openapi/runtime v0.29.2 h1:UmwSGWNmWQqKm1c2MGgXVpC2FTGwPDQeUsBMufc5Yj0= github.com/go-openapi/runtime v0.29.2/go.mod h1:biq5kJXRJKBJxTDJXAa00DOTa/anflQPhT0/wmjuy+0= github.com/go-openapi/spec v0.22.3 h1:qRSmj6Smz2rEBxMnLRBMeBWxbbOvuOoElvSvObIgwQc= github.com/go-openapi/spec v0.22.3/go.mod h1:iIImLODL2loCh3Vnox8TY2YWYJZjMAKYyLH2Mu8lOZs= github.com/go-openapi/strfmt v0.25.0 h1:7R0RX7mbKLa9EYCTHRcCuIPcaqlyQiWNPTXwClK0saQ= github.com/go-openapi/strfmt v0.25.0/go.mod h1:nNXct7OzbwrMY9+5tLX4I21pzcmE6ccMGXl3jFdPfn8= github.com/go-openapi/swag v0.25.4 h1:OyUPUFYDPDBMkqyxOTkqDYFnrhuhi9NR6QVUvIochMU= github.com/go-openapi/swag v0.25.4/go.mod h1:zNfJ9WZABGHCFg2RnY0S4IOkAcVTzJ6z2Bi+Q4i6qFQ= github.com/go-openapi/swag/cmdutils v0.25.4 h1:8rYhB5n6WawR192/BfUu2iVlxqVR9aRgGJP6WaBoW+4= github.com/go-openapi/swag/cmdutils v0.25.4/go.mod h1:pdae/AFo6WxLl5L0rq87eRzVPm/XRHM3MoYgRMvG4A0= github.com/go-openapi/swag/conv v0.25.4 h1:/Dd7p0LZXczgUcC/Ikm1+YqVzkEeCc9LnOWjfkpkfe4= github.com/go-openapi/swag/conv v0.25.4/go.mod h1:3LXfie/lwoAv0NHoEuY1hjoFAYkvlqI/Bn5EQDD3PPU= github.com/go-openapi/swag/fileutils v0.25.4 h1:2oI0XNW5y6UWZTC7vAxC8hmsK/tOkWXHJQH4lKjqw+Y= github.com/go-openapi/swag/fileutils v0.25.4/go.mod h1:cdOT/PKbwcysVQ9Tpr0q20lQKH7MGhOEb6EwmHOirUk= github.com/go-openapi/swag/jsonname v0.25.4 h1:bZH0+MsS03MbnwBXYhuTttMOqk+5KcQ9869Vye1bNHI= github.com/go-openapi/swag/jsonname v0.25.4/go.mod h1:GPVEk9CWVhNvWhZgrnvRA6utbAltopbKwDu8mXNUMag= github.com/go-openapi/swag/jsonutils v0.25.4 h1:VSchfbGhD4UTf4vCdR2F4TLBdLwHyUDTd1/q4i+jGZA= github.com/go-openapi/swag/jsonutils v0.25.4/go.mod h1:7OYGXpvVFPn4PpaSdPHJBtF0iGnbEaTk8AvBkoWnaAY= github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4 h1:IACsSvBhiNJwlDix7wq39SS2Fh7lUOCJRmx/4SN4sVo= github.com/go-openapi/swag/jsonutils/fixtures_test v0.25.4/go.mod h1:Mt0Ost9l3cUzVv4OEZG+WSeoHwjWLnarzMePNDAOBiM= github.com/go-openapi/swag/loading v0.25.4 h1:jN4MvLj0X6yhCDduRsxDDw1aHe+ZWoLjW+9ZQWIKn2s= github.com/go-openapi/swag/loading v0.25.4/go.mod h1:rpUM1ZiyEP9+mNLIQUdMiD7dCETXvkkC30z53i+ftTE= github.com/go-openapi/swag/mangling v0.25.4 h1:2b9kBJk9JvPgxr36V23FxJLdwBrpijI26Bx5JH4Hp48= github.com/go-openapi/swag/mangling v0.25.4/go.mod h1:6dxwu6QyORHpIIApsdZgb6wBk/DPU15MdyYj/ikn0Hg= github.com/go-openapi/swag/netutils v0.25.4 h1:Gqe6K71bGRb3ZQLusdI8p/y1KLgV4M/k+/HzVSqT8H0= github.com/go-openapi/swag/netutils v0.25.4/go.mod h1:m2W8dtdaoX7oj9rEttLyTeEFFEBvnAx9qHd5nJEBzYg= github.com/go-openapi/swag/stringutils v0.25.4 h1:O6dU1Rd8bej4HPA3/CLPciNBBDwZj9HiEpdVsb8B5A8= github.com/go-openapi/swag/stringutils v0.25.4/go.mod h1:GTsRvhJW5xM5gkgiFe0fV3PUlFm0dr8vki6/VSRaZK0= github.com/go-openapi/swag/typeutils v0.25.4 h1:1/fbZOUN472NTc39zpa+YGHn3jzHWhv42wAJSN91wRw= github.com/go-openapi/swag/typeutils v0.25.4/go.mod h1:Ou7g//Wx8tTLS9vG0UmzfCsjZjKhpjxayRKTHXf2pTE= github.com/go-openapi/swag/yamlutils v0.25.4 h1:6jdaeSItEUb7ioS9lFoCZ65Cne1/RZtPBZ9A56h92Sw= github.com/go-openapi/swag/yamlutils v0.25.4/go.mod h1:MNzq1ulQu+yd8Kl7wPOut/YHAAU/H6hL91fF+E2RFwc= github.com/go-openapi/testify/enable/yaml/v2 v2.0.2 h1:0+Y41Pz1NkbTHz8NngxTuAXxEodtNSI1WG1c/m5Akw4= github.com/go-openapi/testify/enable/yaml/v2 v2.0.2/go.mod h1:kme83333GCtJQHXQ8UKX3IBZu6z8T5Dvy5+CW3NLUUg= github.com/go-openapi/testify/v2 v2.0.2 h1:X999g3jeLcoY8qctY/c/Z8iBHTbwLz7R2WXd6Ub6wls= github.com/go-openapi/testify/v2 v2.0.2/go.mod h1:HCPmvFFnheKK2BuwSA0TbbdxJ3I16pjwMkYkP4Ywn54= github.com/go-openapi/validate v0.25.1 h1:sSACUI6Jcnbo5IWqbYHgjibrhhmt3vR6lCzKZnmAgBw= github.com/go-openapi/validate v0.25.1/go.mod h1:RMVyVFYte0gbSTaZ0N4KmTn6u/kClvAFp+mAVfS/DQc= github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-rod/rod v0.116.2 h1:A5t2Ky2A+5eD/ZJQr1EfsQSe5rms5Xof/qj296e+ZqA= github.com/go-rod/rod v0.116.2/go.mod h1:H+CMO9SCNc2TJ2WfrG+pKhITz57uGNYU43qYHh438Mg= github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA= github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ= github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/certificate-transparency-go v1.3.2 h1:9ahSNZF2o7SYMaKaXhAumVEzXB2QaayzII9C8rv7v+A= github.com/google/certificate-transparency-go v1.3.2/go.mod h1:H5FpMUaGa5Ab2+KCYsxg6sELw3Flkl7pGZzWdBoYLXs= github.com/google/flatbuffers v25.2.10+incompatible h1:F3vclr7C3HpB1k9mxCGRMXq6FdUalZ6H/pNX4FP1v0Q= github.com/google/flatbuffers v25.2.10+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo= github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-containerregistry v0.21.3 h1:Xr+yt3VvwOOn/5nJzd7UoOhwPGiPkYW0zWDLLUXqAi4= github.com/google/go-containerregistry v0.21.3/go.mod h1:D5ZrJF1e6dMzvInpBPuMCX0FxURz7GLq2rV3Us9aPkc= github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20260317232201-3888fb8f8738 h1:rOwKr2V11+ajUwz0Qjzfw7FHelubq4aI4FvBUqzyMDE= github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20260317232201-3888fb8f8738/go.mod h1:g6FvB88DCkE3bEDiE0qvSQDxvTFTGs5x0W/GyvwYlKo= github.com/google/go-containerregistry/pkg/authn/kubernetes v0.0.0-20260317232201-3888fb8f8738 h1:he86yi71fRDCdJbVFayjjfx7jcxcopjYW5SNbxmkmv4= github.com/google/go-containerregistry/pkg/authn/kubernetes v0.0.0-20260317232201-3888fb8f8738/go.mod h1:WQf3N6DB+/qX08z4DaUzV94aNRkjlAA04SBjvdXtf6I= github.com/google/go-github/v73 v73.0.0 h1:aR+Utnh+Y4mMkS+2qLQwcQ/cF9mOTpdwnzlaw//rG24= github.com/google/go-github/v73 v73.0.0/go.mod h1:fa6w8+/V+edSU0muqdhCVY7Beh1M8F1IlQPZIANKIYw= github.com/google/go-querystring v1.2.0 h1:yhqkPbu2/OH+V9BfpCVPZkNmUXhb2gBxJArfhIxNtP0= github.com/google/go-querystring v1.2.0/go.mod h1:8IFJqpSRITyJ8QhQ13bmbeMBDfmeEJZD5A0egEOmkqU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20250602020802-c6617b811d0e h1:FJta/0WsADCe1r9vQjdHbd3KuiLPu7Y9WlyLGwMUNyE= github.com/google/pprof v0.0.0-20250602020802-c6617b811d0e/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= github.com/google/trillian v1.7.2 h1:EPBxc4YWY4Ak8tcuhyFleY+zYlbCDCa4Sn24e1Ka8Js= github.com/google/trillian v1.7.2/go.mod h1:mfQJW4qRH6/ilABtPYNBerVJAJ/upxHLX81zxNQw05s= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.11 h1:vAe81Msw+8tKUxi2Dqh/NZMz7475yUvmRIkXr4oN2ao= github.com/googleapis/enterprise-certificate-proxy v0.3.11/go.mod h1:RFV7MUdlb7AgEq2v7FmMCfeSMCllAzWxFgRdusoGks8= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.17.0 h1:RksgfBpxqff0EZkDWYuz9q/uWsTVz+kf43LsZ1J6SMc= github.com/googleapis/gax-go/v2 v2.17.0/go.mod h1:mzaqghpQp4JDh3HvADwrat+6M3MOIDp5YKHhb9PAgDY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= github.com/grpc-ecosystem/grpc-gateway v1.14.6/go.mod h1:zdiPV4Yse/1gnckTHtghG4GkDEdKCRJduHpTxT3/jcw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.5 h1:jP1RStw811EvUDzsUQ9oESqw2e4RqCjSAD9qIL8eMns= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.5/go.mod h1:WXNBZ64q3+ZUemCMXD9kYnr56H7CgZxDBHCVwstfl3s= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48= github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw= github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0 h1:U+kC2dOhMFQctRfhK0gRctKAPTloZdMU5ZJxaesJ/VM= github.com/hashicorp/go-secure-stdlib/parseutil v0.2.0/go.mod h1:Ll013mhdmsVDuoIXVfBtvgGJsXDYkTw1kooNcoCXuE0= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2 h1:kes8mmyCpxJsI7FTwtzRqEy9CdjCtrXrXGuOpxEA7Ts= github.com/hashicorp/go-secure-stdlib/strutil v0.1.2/go.mod h1:Gou2R9+il93BqX25LAKCLuM+y9U2T4hlwvT1yprcna4= github.com/hashicorp/go-sockaddr v1.0.7 h1:G+pTkSO01HpR5qCxg7lxfsFEZaG+C0VssTy/9dbT+Fw= github.com/hashicorp/go-sockaddr v1.0.7/go.mod h1:FZQbEYa1pxkQ7WLpyXJ6cbjpT8q0YgQaK/JakXqGyWw= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c= github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hashicorp/hcl v1.0.1-vault-7 h1:ag5OxFVy3QYTFTJODRzTKVZ6xvdfLLCA1cy/Y6xGI0I= github.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= github.com/hashicorp/vault/api v1.22.0 h1:+HYFquE35/B74fHoIeXlZIP2YADVboaPjaSicHEZiH0= github.com/hashicorp/vault/api v1.22.0/go.mod h1:IUZA2cDvr4Ok3+NtK2Oq/r+lJeXkeCrHRmqdyWfpmGM= github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef h1:A9HsByNhogrvm9cWb28sjiS3i7tcKCkflWFEkHfuAgM= github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/in-toto/attestation v1.1.2 h1:MBFn6lsMq6dptQZJBhalXTcWMb/aJy3V+GX3VYj/V1E= github.com/in-toto/attestation v1.1.2/go.mod h1:gYFddHMZj3DiQ0b62ltNi1Vj5rC879bTmBbrv9CRHpM= github.com/in-toto/in-toto-golang v0.9.0 h1:tHny7ac4KgtsfrG6ybU8gVOZux2H8jN05AXJ9EBM1XU= github.com/in-toto/in-toto-golang v0.9.0/go.mod h1:xsBVrVsHNsB61++S6Dy2vWosKhuA3lUTQd+eF9HdeMo= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgx/v5 v5.7.5 h1:JHGfMnQY+IEtGM63d+NGMjoRpysB2JBwDr5fsngwmJs= github.com/jackc/pgx/v5 v5.7.5/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jdolitsky/glog v0.0.0-20220729172235-78744e90d087/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 h1:TMtDYDHKYY15rFihtRfck/bfFqNfvcabqvXAFQfAUpY= github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267/go.mod h1:h1nSAbGFqGVzn6Jyl1R/iCcBUHN4g+gW1u9CoBTrb9E= github.com/jellydator/ttlcache/v3 v3.4.0 h1:YS4P125qQS0tNhtL6aeYkheEaB/m8HCqdMMP4mnWdTY= github.com/jellydator/ttlcache/v3 v3.4.0/go.mod h1:Hw9EgjymziQD3yGsQdf1FqFdpp7YjFMd4Srg5EJlgD4= github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24 h1:liMMTbpW34dhU4az1GN0pTPADwNmvoRSeoZ6PItiqnY= github.com/jmespath/go-jmespath v0.4.1-0.20220621161143-b0104c826a24/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs= github.com/jmhodges/clock v1.2.0/go.mod h1:qKjhA7x7u/lQpPB1XAqX1b1lCI/w3/fNuYpI/ZjLynI= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU= github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lestrrat-go/blackmagic v1.0.4 h1:IwQibdnf8l2KoO+qC3uT4OaTWsW7tuRQXy9TRN9QanA= github.com/lestrrat-go/blackmagic v1.0.4/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw= github.com/lestrrat-go/dsig v1.0.0 h1:OE09s2r9Z81kxzJYRn07TFM9XA4akrUdoMwr0L8xj38= github.com/lestrrat-go/dsig v1.0.0/go.mod h1:dEgoOYYEJvW6XGbLasr8TFcAxoWrKlbQvmJgCR0qkDo= github.com/lestrrat-go/dsig-secp256k1 v1.0.0 h1:JpDe4Aybfl0soBvoVwjqDbp+9S1Y2OM7gcrVVMFPOzY= github.com/lestrrat-go/dsig-secp256k1 v1.0.0/go.mod h1:CxUgAhssb8FToqbL8NjSPoGQlnO4w3LG1P0qPWQm/NU= github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= github.com/lestrrat-go/httprc/v3 v3.0.1 h1:3n7Es68YYGZb2Jf+k//llA4FTZMl3yCwIjFIk4ubevI= github.com/lestrrat-go/httprc/v3 v3.0.1/go.mod h1:2uAvmbXE4Xq8kAUjVrZOq1tZVYYYs5iP62Cmtru00xk= github.com/lestrrat-go/jwx/v3 v3.0.12 h1:p25r68Y4KrbBdYjIsQweYxq794CtGCzcrc5dGzJIRjg= github.com/lestrrat-go/jwx/v3 v3.0.12/go.mod h1:HiUSaNmMLXgZ08OmGBaPVvoZQgJVOQphSrGr5zMamS8= github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss= github.com/lestrrat-go/option/v2 v2.0.0/go.mod h1:oSySsmzMoR0iRzCDCaUfsCzxQHUEuhOViQObyy7S6Vg= github.com/letsencrypt/boulder v0.20251110.0 h1:J8MnKICeilO91dyQ2n5eBbab24neHzUpYMUIOdOtbjc= github.com/letsencrypt/boulder v0.20251110.0/go.mod h1:ogKCJQwll82m7OVHWyTuf8eeFCjuzdRQlgnZcCl0V+8= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs= github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ= github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.1.2 h1:/VxmeAX5qU6Q3EwafypogwWbYryHFmF2RpkJmw3m4MQ= github.com/miekg/pkcs11 v1.1.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c h1:cqn374mizHuIWj+OSJCajGr/phAmuMug9qIX3l9CflE= github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs= github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/morikuni/aec v1.1.0 h1:vBBl0pUnvi/Je71dsRrhMBtreIqNMYErSAbEeb8jrXQ= github.com/morikuni/aec v1.1.0/go.mod h1:xDRgiq/iw5l+zkao76YTKzKttOp2cwPEne25HDkJnBw= github.com/mozillazg/docker-credential-acr-helper v0.4.0 h1:Uoh3Z9CcpEDnLiozDx+D7oDgRq7X+R296vAqAumnOcw= github.com/mozillazg/docker-credential-acr-helper v0.4.0/go.mod h1:2kiicb3OlPytmlNC9XGkLvVC+f0qTiJw3f/mhmeeQBg= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A= github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 h1:Up6+btDp321ZG5/zdSLo48H9Iaq0UQGthrhWC6pCxzE= github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481/go.mod h1:yKZQO8QE2bHlgozqWDiRVqTFlLQSj30K/6SAK8EeYFw= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY= github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.27.2 h1:LzwLj0b89qtIy6SSASkzlNvX6WktqurSHwkk2ipF/Ns= github.com/onsi/ginkgo/v2 v2.27.2/go.mod h1:ArE1D/XhNXBXCBkKOLkbsb2c81dQHCRcF5zwn/ykDRo= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= github.com/open-policy-agent/opa v1.12.3 h1:qe3m/w52baKC/HJtippw+hYBUKCzuBCPjB+D5P9knfc= github.com/open-policy-agent/opa v1.12.3/go.mod h1:RnDgm04GA1RjEXJvrsG9uNT/+FyBNmozcPvA2qz60M4= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.12.2/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= github.com/prometheus/statsd_exporter v0.22.7/go.mod h1:N/TevpjkIh9ccs6nuzY3jQn9dFqnUakOjnEuMPJJJnI= github.com/prometheus/statsd_exporter v0.22.8 h1:Qo2D9ZzaQG+id9i5NYNGmbf1aa/KxKbB9aKfMS+Yib0= github.com/prometheus/statsd_exporter v0.22.8/go.mod h1:/DzwbTEaFTE0Ojz5PqcSk6+PFHOPWGxdXVr6yC8eFOM= github.com/protocolbuffers/txtpbfmt v0.0.0-20251016062345-16587c79cd91 h1:s1LvMaU6mVwoFtbxv/rCZKE7/fwDmDY684FfUe4c1Io= github.com/protocolbuffers/txtpbfmt v0.0.0-20251016062345-16587c79cd91/go.mod h1:JSbkp0BviKovYYt9XunS95M3mLPibE9bGg+Y95DsEEY= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 h1:bsUq1dX0N8AOIL7EB/X911+m4EHsnWEHeJ0c+3TTBrg= github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= github.com/sassoftware/relic v7.2.1+incompatible h1:Pwyh1F3I0r4clFJXkSI8bOyJINGqpgjJU3DYAZeI05A= github.com/sassoftware/relic v7.2.1+incompatible/go.mod h1:CWfAxv73/iLZ17rbyhIEq3K9hs5w6FpNMdUT//qR+zk= github.com/sassoftware/relic/v7 v7.6.2 h1:rS44Lbv9G9eXsukknS4mSjIAuuX+lMq/FnStgmZlUv4= github.com/sassoftware/relic/v7 v7.6.2/go.mod h1:kjmP0IBVkJZ6gXeAu35/KCEfca//+PKM6vTAsyDPY+k= github.com/secure-systems-lab/go-securesystemslib v0.10.0 h1:l+H5ErcW0PAehBNrBxoGv1jjNpGYdZ9RcheFkB2WI14= github.com/secure-systems-lab/go-securesystemslib v0.10.0/go.mod h1:MRKONWmRoFzPNQ9USRF9i1mc7MvAVvF1LlW8X5VWDvk= github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shibumi/go-pathspec v1.3.0 h1:QUyMZhFo0Md5B8zV8x2tesohbb5kfbpTi9rBnKh5dkI= github.com/shibumi/go-pathspec v1.3.0/go.mod h1:Xutfslp817l2I1cZvgcfeMQJG5QnU2lh5tVaaMCl3jE= github.com/sigstore/cosign/v3 v3.0.5 h1:c1zPqjU+H4wmirgysC+AkWMg7a7fykyOYF/m+F1150I= github.com/sigstore/cosign/v3 v3.0.5/go.mod h1:ble1vMvJagCFyTIDkibCq6MIHiWDw00JNYl0f9rB4T4= github.com/sigstore/protobuf-specs v0.5.0 h1:F8YTI65xOHw70NrvPwJ5PhAzsvTnuJMGLkA4FIkofAY= github.com/sigstore/protobuf-specs v0.5.0/go.mod h1:+gXR+38nIa2oEupqDdzg4qSBT0Os+sP7oYv6alWewWc= github.com/sigstore/rekor v1.5.0 h1:rL7SghHd5HLCtsCrxw0yQg+NczGvM75EjSPPWuGjaiQ= github.com/sigstore/rekor v1.5.0/go.mod h1:D7JoVCUkxwQOpPDNYeu+CE8zeBC18Y5uDo6tF8s2rcQ= github.com/sigstore/rekor-tiles/v2 v2.2.0 h1:QwJNwxT+k5A3id+Hrg+8vYcNsTaB0Sj51xjfW2rKyAs= github.com/sigstore/rekor-tiles/v2 v2.2.0/go.mod h1:/WNRYctHKdxcjgXydYwO5OclW72Zqh6fNHSyGE8zQOE= github.com/sigstore/scaffolding v0.7.22 h1:VjrRzUVRXWGPboglizvGvgq3U8kXnBS5/s4jDCUVwiU= github.com/sigstore/scaffolding v0.7.22/go.mod h1:ojN1gLIjZCl0lhEoqXBvaL+GJbTbBgcNZxxxvK7apuM= github.com/sigstore/sigstore v1.10.4 h1:ytOmxMgLdcUed3w1SbbZOgcxqwMG61lh1TmZLN+WeZE= github.com/sigstore/sigstore v1.10.4/go.mod h1:tDiyrdOref3q6qJxm2G+JHghqfmvifB7hw+EReAfnbI= github.com/sigstore/sigstore-go v1.1.4 h1:wTTsgCHOfqiEzVyBYA6mDczGtBkN7cM8mPpjJj5QvMg= github.com/sigstore/sigstore-go v1.1.4/go.mod h1:2U/mQOT9cjjxrtIUeKDVhL+sHBKsnWddn8URlswdBsg= github.com/sigstore/sigstore/pkg/signature/kms/aws v1.10.4 h1:VZ+L6SKVWbLPHznIF0tBuO7qKMFdJiJMVwFKu9DlY5o= github.com/sigstore/sigstore/pkg/signature/kms/aws v1.10.4/go.mod h1:Rstj47WpJym25il8j4jTL0BfikzP/9AhVD+DsBcYzZc= github.com/sigstore/sigstore/pkg/signature/kms/azure v1.10.4 h1:G7yOv8bxk3zIEEZyVCixPxtePIAm+t3ZWSaKRPzVw+o= github.com/sigstore/sigstore/pkg/signature/kms/azure v1.10.4/go.mod h1:hxJelB/bRItMYOzi6qD9xEKjse2QZcikh4TbysfdDHc= github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.10.4 h1:Qxt6dE4IwhJ6gIXmg2q4S/SeqEDSZ29nmfsv7Zb6LL4= github.com/sigstore/sigstore/pkg/signature/kms/gcp v1.10.4/go.mod h1:hJVeNOwarqfyALjOwsf0OR8YA/A96NABucEaQumPr30= github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.10.4 h1:KVavYMPfSf5NryOl6VrZ9nRG3fXOOJOPp7Czk/YCPkM= github.com/sigstore/sigstore/pkg/signature/kms/hashivault v1.10.4/go.mod h1:J7CA1AaBkyK8dYq6EdQANhj+8oEcsA7PrIp088qgPiY= github.com/sigstore/timestamp-authority/v2 v2.0.4 h1:65IBa4LUeFWDQu9hiTt5lBpi/F5jonJWZtH6VLn4InU= github.com/sigstore/timestamp-authority/v2 v2.0.4/go.mod h1:EXJLiMDBqRPlzC02hPiFSiYTCqSuUpU68a4vr0DFePM= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/stvp/go-udp-testing v0.0.0-20201019212854-469649b16807/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tchap/go-patricia/v2 v2.3.3 h1:xfNEsODumaEcCcY3gI0hYPZ/PcpVv5ju6RMAhgwZDDc= github.com/tchap/go-patricia/v2 v2.3.3/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg= github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU= github.com/theupdateframework/go-tuf v0.7.0 h1:CqbQFrWo1ae3/I0UCblSbczevCCbS31Qvs5LdxRWqRI= github.com/theupdateframework/go-tuf v0.7.0/go.mod h1:uEB7WSY+7ZIugK6R1hiBMBjQftaFzn7ZCDJcp1tCUug= github.com/theupdateframework/go-tuf/v2 v2.4.1 h1:K6ewW064rKZCPkRo1W/CTbTtm/+IB4+coG1iNURAGCw= github.com/theupdateframework/go-tuf/v2 v2.4.1/go.mod h1:Nex2enPVYDFCklrnbTzl3OVwD7fgIAj0J5++z/rvCj8= github.com/tink-crypto/tink-go-awskms/v2 v2.1.0 h1:N9UxlsOzu5mttdjhxkDLbzwtEecuXmlxZVo/ds7JKJI= github.com/tink-crypto/tink-go-awskms/v2 v2.1.0/go.mod h1:PxSp9GlOkKL9rlybW804uspnHuO9nbD98V/fDX4uSis= github.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0 h1:3B9i6XBXNTRspfkTC0asN5W0K6GhOSgcujNiECNRNb0= github.com/tink-crypto/tink-go-gcpkms/v2 v2.2.0/go.mod h1:jY5YN2BqD/KSCHM9SqZPIpJNG/u3zwfLXHgws4x2IRw= github.com/tink-crypto/tink-go-hcvault/v2 v2.4.0 h1:j+S+WKBQ5ya26A5EM/uXoVe+a2IaPQN8KgBJZ22cJ+4= github.com/tink-crypto/tink-go-hcvault/v2 v2.4.0/go.mod h1:OCKJIujnTzDq7f+73NhVs99oA2c1TR6nsOpuasYM6Yo= github.com/tink-crypto/tink-go/v2 v2.6.0 h1:+KHNBHhWH33Vn+igZWcsgdEPUxKwBMEe0QC60t388v4= github.com/tink-crypto/tink-go/v2 v2.6.0/go.mod h1:2WbBA6pfNsAfBwDCggboaHeB2X29wkU8XHtGwh2YIk8= github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 h1:e/5i7d4oYZ+C1wj2THlRK+oAhjeS/TRQwMfkIuet3w0= github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399/go.mod h1:LdwHTNJT99C5fTAzDz0ud328OgXz+gierycbcIx2fRs= github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho= github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE= github.com/transparency-dev/formats v0.0.0-20251017110053-404c0d5b696c h1:5a2XDQ2LiAUV+/RjckMyq9sXudfrPSuCY4FuPC1NyAw= github.com/transparency-dev/formats v0.0.0-20251017110053-404c0d5b696c/go.mod h1:g85IafeFJZLxlzZCDRu4JLpfS7HKzR+Hw9qRh3bVzDI= github.com/transparency-dev/merkle v0.0.2 h1:Q9nBoQcZcgPamMkGn7ghV8XiTZ/kRxn1yCG81+twTK4= github.com/transparency-dev/merkle v0.0.2/go.mod h1:pqSy+OXefQ1EDUVmAJ8MUhHB9TXGuzVAT58PqBoHz1A= github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXVQ= github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= github.com/vbatts/tar-split v0.12.2 h1:w/Y6tjxpeiFMR47yzZPlPj/FcPLpXbTUi/9H7d3CPa4= github.com/vbatts/tar-split v0.12.2/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA= github.com/vektah/gqlparser/v2 v2.5.31 h1:YhWGA1mfTjID7qJhd1+Vxhpk5HTgydrGU9IgkWBTJ7k= github.com/vektah/gqlparser/v2 v2.5.31/go.mod h1:c1I28gSOVNzlfc4WuDlqU7voQnsqI6OG2amkBAFmgts= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/yashtewari/glob-intersection v0.2.0 h1:8iuHdN88yYuCzCdjt0gDe+6bAhUwBeEWqThExu54RFg= github.com/yashtewari/glob-intersection v0.2.0/go.mod h1:LK7pIC3piUjovexikBbJ26Yml7g8xa5bsjfx2v1fwok= github.com/ysmood/fetchup v0.2.3 h1:ulX+SonA0Vma5zUFXtv52Kzip/xe7aj4vqT5AJwQ+ZQ= github.com/ysmood/fetchup v0.2.3/go.mod h1:xhibcRKziSvol0H1/pj33dnKrYyI2ebIvz5cOOkYGns= github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ= github.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18= github.com/ysmood/got v0.40.0 h1:ZQk1B55zIvS7zflRrkGfPDrPG3d7+JOza1ZkNxcc74Q= github.com/ysmood/got v0.40.0/go.mod h1:W7DdpuX6skL3NszLmAsC5hT7JAhuLZhByVzHTq874Qg= github.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE= github.com/ysmood/gson v0.7.3/go.mod h1:3Kzs5zDl21g5F/BlLTNcuAGAYLKt2lV5G8D1zF3RNmg= github.com/ysmood/leakless v0.9.0 h1:qxCG5VirSBvmi3uynXFkcnLMzkphdh3xx5FtrORwDCU= github.com/ysmood/leakless v0.9.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zalando/go-keyring v0.2.6 h1:r7Yc3+H+Ux0+M72zacZoItR3UDxeWfKTcabvkI8ua9s= github.com/zalando/go-keyring v0.2.6/go.mod h1:2TCrxYrbUNYfNS/Kgy/LSrkSQzZ5UPVH85RwfczwvcI= gitlab.com/gitlab-org/api/client-go v1.25.0 h1:9YVk2o1CjZWKh2/KGOsNbOReBSxFIdBv6LrdOnBfEQY= gitlab.com/gitlab-org/api/client-go v1.25.0/go.mod h1:r060AandE8Md/L5oKdUVjljL8YQprOAxKzUnpqWqP3A= go.mongodb.org/mongo-driver v1.17.6 h1:87JUG1wZfWsr6rIz3ZmpH90rL5tea7O3IHuSwHUpsss= go.mongodb.org/mongo-driver v1.17.6/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg= go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho= go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4= go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI= go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo= go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts= go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA= go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc= go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY= go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc= go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= go.step.sm/crypto v0.76.0 h1:K23BSaeoiY7Y5dvvijTeYC9EduDBetNwQYMBwMhi1aA= go.step.sm/crypto v0.76.0/go.mod h1:PXYJdKkK8s+GHLwLguFaLxHNAFsFL3tL1vSBrYfey5k= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= golang.org/x/crypto v0.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4= golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.34.0 h1:xIHgNUUnW6sYkcM5Jleh05DvLOtwc6RitGHbDk4akRI= golang.org/x/mod v0.34.0/go.mod h1:ykgH52iCZe79kzLLMhyCUzhMci+nQj+0XkbXpNYtVjY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/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-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 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-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220708085239-5a0f0661e09d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo= golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/term v0.41.0 h1:QCgPso/Q3RTJx2Th4bDLqML4W6iJiaXFq2/ftQF13YU= golang.org/x/term v0.41.0/go.mod h1:3pfBgksrReYfZ5lvYM0kSO0LIkAl4Yl2bXOkKP7Ec2A= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= golang.org/x/tools/go/expect v0.1.0-deprecated h1:jY2C5HGYR5lqex3gEniOQL0r7Dq5+VGVgY1nudX5lXY= golang.org/x/tools/go/expect v0.1.0-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8= 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= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.25.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= google.golang.org/api v0.267.0 h1:w+vfWPMPYeRs8qH1aYYsFX68jMls5acWl/jocfLomwE= google.golang.org/api v0.267.0/go.mod h1:Jzc0+ZfLnyvXma3UtaTl023TdhZu6OMBP9tJ+0EmFD0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200527145253-8367513e4ece/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20260128011058-8636f8732409 h1:VQZ/yAbAtjkHgH80teYd2em3xtIkkHd7ZhqfH2N9CsM= google.golang.org/genproto v0.0.0-20260128011058-8636f8732409/go.mod h1:rxKD3IEILWEu3P44seeNOAwZN4SaoKaQ/2eTg4mM6EM= google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 h1:merA0rdPeUV3YIIfHHcH4qBkiQAc1nfCKSI7lB4cV2M= google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409/go.mod h1:fl8J1IvUjCilwZzQowmw2b7HQB2eAuYBabMXzWurF+I= google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 h1:Jr5R2J6F6qWyzINc+4AM8t5pfUz6beZpHp678GNrMbE= google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE= google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/evanphx/json-patch.v4 v4.13.0 h1:czT3CmqEaQ1aanPc5SdlgQrrEIb8w/wwCvWWnfEbYzo= gopkg.in/evanphx/json-patch.v4 v4.13.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.1 h1:tVBILHy0R6e4wkYOn3XmiITt/hEVH4TFMYvAX2Ytz6k= gopkg.in/ini.v1 v1.67.1/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.1.0 h1:rVV8Tcg/8jHUkPUorwjaMTtemIMVXfIPKiOqnhEhakk= gotest.tools/v3 v3.1.0/go.mod h1:fHy7eyTmJFO5bQbUsEGQ1v4m2J3Jz9eWL54TP2/ZuYQ= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.35.2 h1:tW7mWc2RpxW7HS4CoRXhtYHSzme1PN1UjGHJ1bdrtdw= k8s.io/api v0.35.2/go.mod h1:7AJfqGoAZcwSFhOjcGM7WV05QxMMgUaChNfLTXDRE60= k8s.io/apiextensions-apiserver v0.27.6 h1:mOwSBJtThZhpJr+8gEkc3wFDIjq87E3JspR5mtZxIg8= k8s.io/apiextensions-apiserver v0.27.6/go.mod h1:AVNlLYRrESG5Poo6ASRUhY2pvoKPcNt8y/IuZ4lx3o8= k8s.io/apimachinery v0.35.2 h1:NqsM/mmZA7sHW02JZ9RTtk3wInRgbVxL8MPfzSANAK8= k8s.io/apimachinery v0.35.2/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns= k8s.io/client-go v0.35.2 h1:YUfPefdGJA4aljDdayAXkc98DnPkIetMl4PrKX97W9o= k8s.io/client-go v0.35.2/go.mod h1:4QqEwh4oQpeK8AaefZ0jwTFJw/9kIjdQi0jpKeYvz7g= k8s.io/code-generator v0.29.4 h1:8ESudFNbY5/9BzB8KOEFG2uV9Q0AQxkc4mrQESr30Ks= k8s.io/code-generator v0.29.4/go.mod h1:7TYnI0dYItL2cKuhhgPSuF3WED9uMdELgbVXFfn/joE= k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01 h1:pWEwq4Asjm4vjW7vcsmijwBhOr1/shsbSYiWXmNGlks= k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f h1:SLb+kxmzfA87x4E4brQzB33VBbT2+x7Zq9ROIHmGn9Q= k8s.io/gengo/v2 v2.0.0-20250604051438-85fd79dbfd9f/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE= k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= knative.dev/hack v0.0.0-20240111013919-e89096d74d85 h1:ERgPObDcW9LfaEPAeFvbW3UJcF3C3ul6B2ErNMv13OE= knative.dev/hack v0.0.0-20240111013919-e89096d74d85/go.mod h1:yk2OjGDsbEnQjfxdm0/HJKS2WqTLEFg/N6nUs6Rqx3Q= knative.dev/hack/schema v0.0.0-20240607132042-09143140a254 h1:b9hFHGtxx0Kpm4EEjSD72lL0jms91To3OEVBTbqfOYI= knative.dev/hack/schema v0.0.0-20240607132042-09143140a254/go.mod h1:3pWwBLnTZSM9psSgCAvhKOHIPTzqfEMlWRpDu6IYhK0= knative.dev/pkg v0.0.0-20230612155445-74c4be5e935e h1:koM+NopG2Yw738NlJhQF3ZwpyS+HHznuLm294VYlUKg= knative.dev/pkg v0.0.0-20230612155445-74c4be5e935e/go.mod h1:dqC6IrvyBE7E+oZocs5PkVhq1G59pDTA7r8U17EAKMk= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/release-utils v0.12.3 h1:iNVJY81QfmMCmXxMg8IvvkkeQNk6ZWlLj+iPKSlKyVQ= sigs.k8s.io/release-utils v0.12.3/go.mod h1:BvbNmm1BmM3cnEpBmNHWL3wOSziOdGlsYR8vCFq/Q0o= sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco= sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= ================================================ FILE: hack/boilerplate/boilerplate.go.txt ================================================ // 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. ================================================ FILE: hack/gentestdata/gentestdata.go ================================================ // 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. package main import ( "bytes" "context" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "flag" "log" "math/big" "os" "path" "path/filepath" "time" "github.com/sigstore/cosign/v3/pkg/cosign" "github.com/sigstore/policy-controller/pkg/apis/config" testing "github.com/sigstore/policy-controller/pkg/reconciler/testing/v1alpha1" pbcommon "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" "github.com/sigstore/scaffolding/pkg/repo" "github.com/sigstore/sigstore/pkg/cryptoutils" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/types/known/timestamppb" ) // This program generates test data for the trustroot reconciler. // // To run this program, you can use the following command from the root of the repo: // $ go run hack/gentestdata/gentestdata.go // or, // $ make generate-testdata // // The output of this program can be used to update the `marshalledEntry.json` // file in the `pkg/reconciler/trustroot/testdata` package. // // Do not rely on the output of this program to produce valid results. Always // verify the output manually before committing. var ( dir = flag.String("output-dir", "pkg/reconciler/trustroot/testdata", "Output directory") ) func main() { flag.Parse() ctfePK, ctfeLogID := genPK() rekorPK, rekorLogID := genPK() fulcioChain := genCertChain(x509.KeyUsage(x509.ExtKeyUsageCodeSigning)) fulcioChainConcat := bytes.Join(fulcioChain, nil) tsaChain := genCertChain(x509.KeyUsage(x509.ExtKeyUsageTimeStamping)) tsaChainConcat := bytes.Join(tsaChain, nil) sigstoreKeysMap := map[string]string{ "ctfe": string(ctfePK), "fulcio": string(fulcioChainConcat), "rekor": string(rekorPK), "tsa": string(tsaChainConcat), } marshalledEntry, err := genTrustRoot(sigstoreKeysMap) if err != nil { log.Fatal(err) } tufRepo, rootJSON, err := genTUFRepo(map[string][]byte{ "rekor.pem": []byte(sigstoreKeysMap["rekor"]), "ctfe.pem": []byte(sigstoreKeysMap["ctfe"]), "fulcio.pem": []byte(sigstoreKeysMap["fulcio"]), }) if err != nil { log.Fatal(err) } tufRepoWithTrustedRootJSON, rootJSONWithTrustedRootJSON, err := genTUFRepo(map[string][]byte{ "trusted_root.json": marshalledEntry, }) if err != nil { log.Fatal(err) } tufRepoWithCustomTrustedRootJSON, rootJSONWithCustomTrustedRootJSON, err := genTUFRepo(map[string][]byte{ "custom_trusted_root.json": marshalledEntry, }) if err != nil { log.Fatal(err) } marshalledEntryFromMirrorFS, err := genTrustedRoot(sigstoreKeysMap) if err != nil { log.Fatal(err) } mustWriteFile("ctfePublicKey.pem", ctfePK) mustWriteFile("ctfeLogID.txt", []byte(ctfeLogID)) mustWriteFile("rekorPublicKey.pem", rekorPK) mustWriteFile("rekorLogID.txt", []byte(rekorLogID)) mustWriteFile("fulcioCertChain.pem", fulcioChainConcat) mustWriteFile("tsaCertChain.pem", tsaChainConcat) mustWriteFile("marshalledEntry.json", marshalledEntry) mustWriteFile("marshalledEntryFromMirrorFS.json", marshalledEntryFromMirrorFS) mustWriteFile("tufRepo.tar", tufRepo) mustWriteFile("root.json", rootJSON) mustWriteFile("tufRepoWithTrustedRootJSON.tar", tufRepoWithTrustedRootJSON) mustWriteFile("rootWithTrustedRootJSON.json", rootJSONWithTrustedRootJSON) mustWriteFile("tufRepoWithCustomTrustedRootJSON.tar", tufRepoWithCustomTrustedRootJSON) mustWriteFile("rootWithCustomTrustedRootJSON.json", rootJSONWithCustomTrustedRootJSON) } func mustWriteFile(path string, data []byte) { err := os.WriteFile(filepath.Join(*dir, path), data, 0600) if err != nil { log.Fatalf("failed to write file %s: %v", path, err) } } func genPK() ([]byte, string) { priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { log.Fatalf("failed to generate ecdsa key: %v", err) } der, err := x509.MarshalPKIXPublicKey(priv.Public().(*ecdsa.PublicKey)) if err != nil { log.Fatalf("failed to marshal ecdsa key: %v", err) } pemPK := pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: der}) // generate log id pk, err := cryptoutils.UnmarshalPEMToPublicKey(pemPK) if err != nil { log.Fatalf("failed to unmarshal ecdsa key: %v", err) } logID, err := cosign.GetTransparencyLogID(pk) if err != nil { log.Fatalf("failed to get transparency log id: %v", err) } return pemPK, logID } func genCertChain(keyUsage x509.KeyUsage) [][]byte { // Create a new CA certificate caPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { log.Fatalf("failed to generate ecdsa key: %v", err) } template := &x509.Certificate{ SerialNumber: new(big.Int).SetInt64(1), Subject: pkix.Name{CommonName: "ca"}, NotBefore: time.Now(), NotAfter: time.Now().AddDate(10, 0, 0), KeyUsage: x509.KeyUsageCertSign, BasicConstraintsValid: true, IsCA: true, } caCertBytes, err := x509.CreateCertificate(rand.Reader, template, template, caPriv.Public(), caPriv) if err != nil { log.Fatalf("failed to create x509 certificate: %v", err) } caCert, err := x509.ParseCertificate(caCertBytes) if err != nil { log.Fatalf("failed to parse x509 certificate: %v", err) } // Create a new leaf certificate leafPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { log.Fatalf("failed to generate ecdsa key: %v", err) } leafCert, err := x509.CreateCertificate(rand.Reader, &x509.Certificate{ SerialNumber: new(big.Int).SetInt64(2), Subject: pkix.Name{CommonName: "leaf"}, NotBefore: time.Now(), NotAfter: time.Now().AddDate(10, 0, 0), KeyUsage: keyUsage, }, caCert, &leafPriv.PublicKey, caPriv) if err != nil { log.Fatalf("failed to create x509 certificate: %v", err) } return [][]byte{pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: leafCert}), pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: caCertBytes})} } func genTrustRoot(sigstoreKeysMap map[string]string) (marshalledEntry []byte, err error) { trustRoot := testing.NewTrustRoot("test-trustroot", testing.WithSigstoreKeys(sigstoreKeysMap)) sigstoreKeys, err := config.ConvertSigstoreKeys(context.Background(), trustRoot.Spec.SigstoreKeys) if err != nil { return nil, err } err = populateLogIDs(sigstoreKeys) if err != nil { return nil, err } return []byte(protojson.Format(sigstoreKeys)), nil } func populateLogIDs(sigstoreKeys *config.SigstoreKeys) error { for i := range sigstoreKeys.Tlogs { logID, err := genLogID(sigstoreKeys.Tlogs[i].PublicKey.RawBytes) if err != nil { return err } sigstoreKeys.Tlogs[i].LogId = &config.LogID{KeyId: []byte(logID)} } for i := range sigstoreKeys.Ctlogs { logID, err := genLogID(sigstoreKeys.Ctlogs[i].PublicKey.RawBytes) if err != nil { return err } sigstoreKeys.Ctlogs[i].LogId = &config.LogID{KeyId: []byte(logID)} } return nil } func genLogID(pkBytes []byte) (string, error) { pk, err := x509.ParsePKIXPublicKey(pkBytes) if err != nil { return "", err } return cosign.GetTransparencyLogID(pk) } func genTUFRepo(files map[string][]byte) ([]byte, []byte, error) { defer os.RemoveAll(path.Join(os.TempDir(), "tuf")) // TODO: Update scaffolding to use os.MkdirTemp and remove this ctx := context.Background() local, dir, err := repo.CreateRepoWithOptions(ctx, files, repo.CreateRepoOptions{AddMetadataTargets: true}) if err != nil { return nil, nil, err } meta, err := local.GetMeta() if err != nil { return nil, nil, err } rootJSON, ok := meta["root.json"] if !ok { return nil, nil, err } var compressed bytes.Buffer if err := repo.CompressFS(os.DirFS(dir), &compressed, map[string]bool{"keys": true, "staged": true}); err != nil { return nil, nil, err } return compressed.Bytes(), rootJSON, nil } func genTrustedRoot(sigstoreKeysMap map[string]string) ([]byte, error) { tlogKey, _, err := config.DeserializePublicKey([]byte(sigstoreKeysMap["rekor"])) if err != nil { return nil, err } ctlogKey, _, err := config.DeserializePublicKey([]byte(sigstoreKeysMap["ctfe"])) if err != nil { return nil, err } certChain, err := config.DeserializeCertChain([]byte(sigstoreKeysMap["fulcio"])) if err != nil { return nil, err } trustRoot := &config.SigstoreKeys{ CertificateAuthorities: []*config.CertificateAuthority{{ CertChain: certChain, ValidFor: &config.TimeRange{Start: ×tamppb.Timestamp{}}, }}, Tlogs: []*config.TransparencyLogInstance{{ HashAlgorithm: pbcommon.HashAlgorithm_SHA2_256, PublicKey: tlogKey, }}, Ctlogs: []*config.TransparencyLogInstance{{ HashAlgorithm: pbcommon.HashAlgorithm_SHA2_256, PublicKey: ctlogKey, }}, } err = populateLogIDs(trustRoot) if err != nil { return nil, err } trustRootBytes := []byte(protojson.Format(trustRoot)) return trustRootBytes, nil } ================================================ FILE: hack/github-oidc-setup.sh ================================================ #!/usr/bin/env bash # 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. # Idempotent script. # # Commands based off of Google blog post # https://cloud.google.com/blog/products/identity-security/enabling-keyless-authentication-from-github-actions # # One addition is the attribute.repository=assertion.repository mapping. # This allows it to be pinned to given repo. set -o errexit set -o nounset set -o pipefail set -o verbose set -o xtrace PROJECT_ID="projectsigstore" PROJECT_NUMBER="498091336538" POOL_NAME="githubactions" PROVIDER_NAME="sigstore-cosign" LOCATION="global" REPO="sigstore/cosign" SERVICE_ACCOUNT_ID="github-actions-cosign" SERVICE_ACCOUNT="${SERVICE_ACCOUNT_ID}@${PROJECT_ID}.iam.gserviceaccount.com" # Create workload identity pool if not present. if ! (gcloud iam workload-identity-pools describe "${POOL_NAME}" --location=${LOCATION}); then gcloud iam workload-identity-pools create "${POOL_NAME}" \ --project="${PROJECT_ID}" \ --location="${LOCATION}" \ --display-name="Github Actions Pool" fi # Create workload identity provider if not present. if ! (gcloud iam workload-identity-pools providers describe "${PROVIDER_NAME}" --location="${LOCATION}" --workload-identity-pool="${POOL_NAME}"); then gcloud iam workload-identity-pools providers create-oidc "${PROVIDER_NAME}" \ --project="${PROJECT_ID}" \ --location="${LOCATION}" \ --workload-identity-pool="${POOL_NAME}" \ --display-name="Github Actions Provider Cosign" \ --attribute-mapping="google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.aud=assertion.aud,attribute.repository=assertion.repository" \ --issuer-uri="https://token.actions.githubusercontent.com" fi # Create service account if not present. if ! (gcloud iam service-accounts describe "${SERVICE_ACCOUNT}"); then gcloud iam service-accounts create ${SERVICE_ACCOUNT_ID} \ --description="Service account for Github Actions Cosign" \ --display-name="Github Actions Cosign" fi # Adding binding is idempotent. gcloud iam service-accounts add-iam-policy-binding "${SERVICE_ACCOUNT}" \ --project="${PROJECT_ID}" \ --role="roles/iam.workloadIdentityUser" \ --member="principalSet://iam.googleapis.com/projects/${PROJECT_NUMBER}/locations/${LOCATION}/workloadIdentityPools/${POOL_NAME}/attribute.repository/${REPO}" # Adding binding is idempotent. # Used for kicking off cloud build. gcloud projects add-iam-policy-binding "${PROJECT_ID}" \ --project="${PROJECT_ID}" \ --role="roles/cloudbuild.builds.editor" \ --member="serviceAccount:${SERVICE_ACCOUNT}" # Adding binding is idempotent. # Permission needed to run `gcloud builds` # https://cloud.google.com/build/docs/securing-builds/configure-access-to-resources#granting_permissions_to_run_gcloud_commands gcloud projects add-iam-policy-binding "${PROJECT_ID}" \ --project="${PROJECT_ID}" \ --role="roles/serviceusage.serviceUsageConsumer" \ --member="serviceAccount:${SERVICE_ACCOUNT}" ================================================ FILE: hack/tools.go ================================================ //go:build tools // +build tools // 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. package tools // This package imports things required by this repository, to force `go mod` to see them as dependencies import ( _ "k8s.io/code-generator" _ "knative.dev/hack" // codegen: hack/generate-knative.sh _ "knative.dev/pkg/hack" _ "k8s.io/code-generator/cmd/client-gen" _ "k8s.io/code-generator/cmd/deepcopy-gen" _ "k8s.io/code-generator/cmd/defaulter-gen" _ "k8s.io/code-generator/cmd/informer-gen" _ "k8s.io/code-generator/cmd/lister-gen" _ "k8s.io/kube-openapi/cmd/openapi-gen" _ "knative.dev/pkg/codegen/cmd/injection-gen" ) ================================================ FILE: hack/update-codegen.sh ================================================ #!/usr/bin/env bash # 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. set -o errexit set -o nounset set -o pipefail pushd $(dirname "$0")/.. # Removed by update-deps echo === Vendoring scripts go mod vendor source $(dirname $0)/../vendor/knative.dev/hack/codegen-library.sh TMP_DIR="$(mktemp -d)" trap 'rm -rf ${TMP_DIR}' EXIT # Use the same go mod cache to speed things up. export GOMODCACHE=${GOPATH}/pkg/mod export GOPATH=${TMP_DIR} TMP_REPO_PATH="${TMP_DIR}/src/github.com/sigstore/policy-controller" mkdir -p "$(dirname "${TMP_REPO_PATH}")" && ln -s "${REPO_ROOT_DIR}" "${TMP_REPO_PATH}" echo "=== Update Codegen for ${MODULE_NAME}" group "Kubernetes Codegen" # generate the code with: # --output-base because this script should also be able to run inside the vendor dir of # k8s.io/kubernetes. The output-base is needed for the generators to output into the vendor dir # instead of the $GOPATH directly. For normal projects this can be dropped. bash "${CODEGEN_PKG}/kube_codegen.sh" "deepcopy,client,informer,lister" \ github.com/sigstore/policy-controller/pkg/client github.com/sigstore/policy-controller/pkg/apis \ "policy:v1alpha1 policy:v1beta1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt group "ducks" bash "${CODEGEN_PKG}/kube_codegen.sh" "deepcopy" \ github.com/sigstore/policy-controller/pkg/client github.com/sigstore/policy-controller/pkg/apis \ "duck:v1beta1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt group "Knative Codegen" # Knative Injection ${KNATIVE_CODEGEN_PKG}/hack/generate-knative.sh "injection" \ github.com/sigstore/policy-controller/pkg/client github.com/sigstore/policy-controller/pkg/apis \ "policy:v1alpha1 policy:v1beta1 duck:v1beta1" \ --go-header-file ${REPO_ROOT_DIR}/hack/boilerplate/boilerplate.go.txt group "Update CRD Schema" # Note that we run this twice, once for each version of the api, hence the # index of [0,1] so that we get both API descriptions updated. go run $(dirname $0)/../cmd/schema/ dump ClusterImagePolicy \ | yq eval-all --inplace 'select(fileIndex == 0).spec.versions[0].schema.openAPIV3Schema = select(fileIndex == 1) | select(fileIndex == 0)' \ $(dirname $0)/../config/300-clusterimagepolicy.yaml - go run $(dirname $0)/../cmd/schema/ dump ClusterImagePolicy \ | yq eval-all --inplace 'select(fileIndex == 0).spec.versions[1].schema.openAPIV3Schema = select(fileIndex == 1) | select(fileIndex == 0)' \ $(dirname $0)/../config/300-clusterimagepolicy.yaml - # Create file for TrustRoot as well go run $(dirname $0)/../cmd/schema/ dump TrustRoot \ | yq eval-all --inplace 'select(fileIndex == 0).spec.versions[0].schema.openAPIV3Schema = select(fileIndex == 1) | select(fileIndex == 0)' \ $(dirname $0)/../config/300-trustroot.yaml - group "Update deps post-codegen" # Make sure our dependencies are up-to-date ${REPO_ROOT_DIR}/hack/update-deps.sh ================================================ FILE: hack/update-deps.sh ================================================ #!/usr/bin/env bash # 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. set -o errexit set -o nounset set -o pipefail pushd $(dirname "$0")/.. echo === Vendoring scripts go mod vendor source $(dirname "$0")/../vendor/knative.dev/hack/library.sh go_update_deps "$@" echo === Removing vendor/ rm -rf $REPO_ROOT_DIR/vendor/ ================================================ FILE: images/dot/signatures.dot ================================================ digraph { compound=true; rankdir="LR"; ordering = in; subgraph cluster_registry { label = "registry"; subgraph cluster_tags { label = "/v2/.../tags/list"; tag [label="tag", shape="rect"]; tag2 [label="tag", shape="rect"]; } subgraph cluster_manifests { label = "/v2/.../manifests/"; subgraph cluster_image { label = "image"; mconfig [label="config", shape="rect"]; layers [label="layers", shape="rect"]; } subgraph cluster_index { label = "signature index"; imanifest [label="manifests", shape="rect"]; } } subgraph cluster_blobs { label = "/v2/.../blobs/"; bconfig [label="config", shape="hexagon"]; l1 [label="layer", shape="folder"]; l2 [label="layer", shape="folder"]; desc1 [label="descriptor", shape="rect", color="green"]; desc2 [label="descriptor", shape="rect", color="green"]; } layers -> l1; layers -> l2; mconfig -> bconfig; imanifest -> desc1 [color="green"]; imanifest -> desc2 [color="green"]; desc1 -> mconfig [lhead=cluster_image, color="green"]; desc2 -> mconfig [lhead=cluster_image, color="green"]; tag -> mconfig [style="dashed", lhead=cluster_image]; tag2 -> imanifest [style="dashed", lhead=cluster_index]; } } ================================================ FILE: pkg/apis/config/doc.go ================================================ // // 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. // +k8s:deepcopy-gen=package // Package config holds the typed objects that define the schemas for // ConfigMap objects that pertain to our API objects. // This ConfigMap gets created by the Reconciler by combining all the // ClusterImagePolicy CR into a single ConfigMap so that the AdmissionController // only needs to deal with a single resource when validationg. package config ================================================ FILE: pkg/apis/config/image_policies.go ================================================ // // 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. package config import ( "encoding/json" "errors" "fmt" "github.com/sigstore/policy-controller/pkg/apis/glob" webhookcip "github.com/sigstore/policy-controller/pkg/webhook/clusterimagepolicy" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metalabels "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime/schema" "sigs.k8s.io/yaml" ) const ( // ImagePoliciesConfigName is the name of ConfigMap created by the // reconciler and consumed by the admission webhook. ImagePoliciesConfigName = "config-image-policies" ) type ImagePolicyConfig struct { // This is the list of ImagePolicies that a admission controller uses // to make policy decisions. Policies map[string]webhookcip.ClusterImagePolicy } // NewImagePoliciesConfigFromMap creates an ImagePolicyConfig from the supplied // Map func NewImagePoliciesConfigFromMap(data map[string]string) (*ImagePolicyConfig, error) { ret := &ImagePolicyConfig{Policies: make(map[string]webhookcip.ClusterImagePolicy, len(data))} // Spin through the ConfigMap. Each key will point to resolved // ImagePatterns. for k, v := range data { // This is the example that we use to document / test the ConfigMap. if k == "_example" { continue } if v == "" { return nil, fmt.Errorf("configmap has an entry %q but no value", k) } clusterImagePolicy := &webhookcip.ClusterImagePolicy{} if err := parseEntry(v, clusterImagePolicy); err != nil { return nil, fmt.Errorf("failed to parse the entry %q : %q : %w", k, v, err) } ret.Policies[k] = *clusterImagePolicy } return ret, nil } // NewImagePoliciesConfigFromConfigMap creates a Features from the supplied ConfigMap func NewImagePoliciesConfigFromConfigMap(config *corev1.ConfigMap) (*ImagePolicyConfig, error) { return NewImagePoliciesConfigFromMap(config.Data) } func parseEntry(entry string, out interface{}) error { j, err := yaml.YAMLToJSON([]byte(entry)) if err != nil { return fmt.Errorf("config's value could not be converted to JSON: %w : %s", err, entry) } return json.Unmarshal(j, &out) } // GetMatchingPolicies returns all matching Policies and their Authorities that // need to be matched for the given kind, version and labels (if provided) to then match the Image. // Returned map contains the name of the CIP as the key, and a normalized // ClusterImagePolicy for it. func (p *ImagePolicyConfig) GetMatchingPolicies(image string, kind, apiVersion string, labels map[string]string) (map[string]webhookcip.ClusterImagePolicy, error) { if p == nil { return nil, errors.New("config is nil") } gv, err := schema.ParseGroupVersion(apiVersion) if err != nil { return nil, err } // While unsafe, this is correct (safe!) for everything we care about. gvr, _ := meta.UnsafeGuessKindToResource(gv.WithKind(kind)) var lastError error ret := make(map[string]webhookcip.ClusterImagePolicy) // TODO(vaikas): this is very inefficient, we should have a better // way to go from image to Authorities, but just seeing if this is even // workable so fine for now. for k, v := range p.Policies { if len(v.Match) > 0 { foundMatch := false for _, matchResource := range v.Match { if matchResource.Resource != gvr.Resource { // Resource doesn't match. continue } if matchResource.Version != gvr.Version && matchResource.Version != "*" { // Version doesn't match exactly or wildcard. continue } if matchResource.Group != gvr.Group { // Group doesn't match. continue } if matchResource.ResourceSelector != nil { selector, err := metav1.LabelSelectorAsSelector(matchResource.ResourceSelector) if err != nil { return nil, errors.New("policy with wrong match label selector") } if !selector.Matches(metalabels.Set(labels)) { continue } } // We found a set of match criteria that this resource satisfies foundMatch = true break } if !foundMatch { // We didn't find any match with the current resource types, so we continue looking for policies continue } } for _, pattern := range v.Images { if pattern.Glob != "" { if matched, err := glob.Match(pattern.Glob, image); err != nil { lastError = err } else if matched { ret[k] = v } } } } return ret, lastError } ================================================ FILE: pkg/apis/config/image_policies_test.go ================================================ // 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. package config import ( "crypto" "crypto/x509" "encoding/pem" "fmt" "strings" "testing" webhookcip "github.com/sigstore/policy-controller/pkg/webhook/clusterimagepolicy" . "knative.dev/pkg/configmap/testing" _ "knative.dev/pkg/system/testing" ) const ( // Just some public key that was laying around, only format matters. inlineKeyData = `-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J RCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ== -----END PUBLIC KEY-----` ) func TestDefaultsConfigurationFromFile(t *testing.T) { _, example := ConfigMapsFromTestFile(t, ImagePoliciesConfigName) if _, err := NewImagePoliciesConfigFromConfigMap(example); err != nil { t.Error("NewImagePoliciesConfigFromConfigMap(example) =", err) } } func TestGetAuthorities(t *testing.T) { // TODO: Clean up this test to be table-driven with sub-tests, instead of one big test. getAuthority := func(t *testing.T, m map[string]webhookcip.ClusterImagePolicy, mp string) webhookcip.Authority { t.Helper() cip, found := m[mp] if !found { t.Fatalf("failed to find matching policy %q", mp) } if len(cip.Authorities) == 0 { t.Fatalf("no authorities for matching policy %q", mp) } return cip.Authorities[0] } _, example := ConfigMapsFromTestFile(t, ImagePoliciesConfigName) defaults, err := NewImagePoliciesConfigFromConfigMap(example) if err != nil { t.Error("NewImagePoliciesConfigFromConfigMap(example) =", err) } c, err := defaults.GetMatchingPolicies("rando", "Pod", "v1", map[string]string{}) checkGetMatches(t, c, err) matchedPolicy := "cluster-image-policy-0" want := inlineKeyData if got := getAuthority(t, c, matchedPolicy).Key.Data; got != want { t.Errorf("Did not get what I wanted %q, got %+v", want, got) } // Make sure UID and ResourceVersion are unserialized properly checkUIDAndResourceVersion(t, matchedPolicy, c[matchedPolicy]) // Make sure glob matches 'randomstuff*' c, err = defaults.GetMatchingPolicies("randomstuffhere", "Pod", "v1", map[string]string{}) checkGetMatches(t, c, err) matchedPolicy = "cluster-image-policy-1" want = inlineKeyData if got := getAuthority(t, c, matchedPolicy).Key.Data; got != want { t.Errorf("Did not get what I wanted %q, got %+v", want, got) } // Make sure UID and ResourceVersion are unserialized properly checkUIDAndResourceVersion(t, matchedPolicy, c[matchedPolicy]) c, err = defaults.GetMatchingPolicies("rando3", "Pod", "v1", map[string]string{}) matchedPolicy = "cluster-image-policy-2" checkGetMatches(t, c, err) want = inlineKeyData if got := getAuthority(t, c, matchedPolicy).Keyless.CACert.Data; got != want { t.Errorf("Did not get what I wanted %q, got %+v", want, got) } wantInsecureIgnoreSCT := true if got := getAuthority(t, c, matchedPolicy).Keyless.InsecureIgnoreSCT; *got != wantInsecureIgnoreSCT { t.Errorf("Did not get what I wanted %v, got %+v", wantInsecureIgnoreSCT, got) } want = "issuer" if got := getAuthority(t, c, matchedPolicy).Keyless.Identities[0].Issuer; got != want { t.Errorf("Did not get what I wanted %q, got %+v", want, got) } want = "subject" if got := getAuthority(t, c, matchedPolicy).Keyless.Identities[0].Subject; got != want { t.Errorf("Did not get what I wanted %q, got %+v", want, got) } want = "trustroot-tsa-ref" got := getAuthority(t, c, matchedPolicy) if got.RFC3161Timestamp.TrustRootRef != want { t.Errorf("Did not get the tsa what I wanted %q, got %+v", want, got) } // Make sure UID and ResourceVersion are unserialized properly checkUIDAndResourceVersion(t, matchedPolicy, c[matchedPolicy]) // Make sure regex matches "regexstring*" c, err = defaults.GetMatchingPolicies("regexstringstuff", "Pod", "v1", map[string]string{}) checkGetMatches(t, c, err) matchedPolicy = "cluster-image-policy-4" want = inlineKeyData if got := getAuthority(t, c, matchedPolicy).Key.Data; got != want { t.Errorf("Did not get what I wanted %q, got %+v", want, got) } checkPublicKey(t, getAuthority(t, c, matchedPolicy).Key.PublicKeys[0]) // Make sure UID and ResourceVersion are unserialized properly checkUIDAndResourceVersion(t, matchedPolicy, c[matchedPolicy]) // Test multiline yaml cert c, err = defaults.GetMatchingPolicies("inlinecert", "Pod", "v1", map[string]string{}) checkGetMatches(t, c, err) matchedPolicy = "cluster-image-policy-3" want = inlineKeyData if got := getAuthority(t, c, matchedPolicy).Key.Data; got != want { t.Errorf("Did not get what I wanted %q, got %+v", want, got) } checkPublicKey(t, getAuthority(t, c, matchedPolicy).Key.PublicKeys[0]) // Test multiline cert but json encoded c, err = defaults.GetMatchingPolicies("ghcr.io/example/foo", "Pod", "v1", map[string]string{}) checkGetMatches(t, c, err) matchedPolicy = "cluster-image-policy-json" want = inlineKeyData if got := getAuthority(t, c, matchedPolicy).Key.Data; got != want { t.Errorf("Did not get what I wanted %q, got %+v", want, got) } checkPublicKey(t, getAuthority(t, c, matchedPolicy).Key.PublicKeys[0]) // Test multiple matches c, err = defaults.GetMatchingPolicies("regexstringtoo", "Pod", "v1", map[string]string{}) checkGetMatches(t, c, err) if len(c) != 2 { t.Errorf("Wanted two matches, got %d", len(c)) } matchedPolicy = "cluster-image-policy-4" want = inlineKeyData if got := getAuthority(t, c, matchedPolicy).Key.Data; got != want { t.Errorf("Did not get what I wanted %q, got %+v", want, got) } checkPublicKey(t, getAuthority(t, c, matchedPolicy).Key.PublicKeys[0]) matchedPolicy = "cluster-image-policy-5" want = inlineKeyData if got := getAuthority(t, c, matchedPolicy).Key.Data; got != want { t.Errorf("Did not get what I wanted %q, got %+v", want, got) } // Test attestations + top level policy c, err = defaults.GetMatchingPolicies("withattestations", "Pod", "v1", map[string]string{}) checkGetMatches(t, c, err) if len(c) != 1 { t.Errorf("Wanted 1 match, got %d", len(c)) } matchedPolicy = "cluster-image-policy-with-policy-attestations" want = "attestation-0" if got := getAuthority(t, c, matchedPolicy).Name; got != want { t.Errorf("Did not get what I wanted %q, got %+v", want, got) } // Both top & authority policy is using cue want = "cue" if got := c[matchedPolicy].Policy.Type; got != want { t.Errorf("Did not get what I wanted %q, got %+v", want, got) } want = "cip level cue here" if got := c[matchedPolicy].Policy.Data; got != want { t.Errorf("Did not get what I wanted %q, got %+v", want, got) } want = "cue" if got := getAuthority(t, c, matchedPolicy).Attestations[0].Type; got != want { t.Errorf("Did not get what I wanted %q, got %+v", want, got) } want = "test-cue-here" if got := getAuthority(t, c, matchedPolicy).Attestations[0].Data; got != want { t.Errorf("Did not get what I wanted %q, got %+v", want, got) } // Test source oci matchedPolicy = "cluster-image-policy-source-oci" c, err = defaults.GetMatchingPolicies("sourceocionly", "Pod", "v1", map[string]string{}) checkGetMatches(t, c, err) if len(c) != 1 { t.Errorf("Wanted 1 match, got %d", len(c)) } checkSourceOCI(t, c[matchedPolicy].Authorities) want = "example.registry.com/alternative/signature" if got := getAuthority(t, c, matchedPolicy).Sources[0].OCI; got != want { t.Errorf("Did not get what I wanted %q, got %+v", want, got) } // Test source signaturePullSecrets matchedPolicy = "cluster-image-policy-source-oci-signature-pull-secrets" c, err = defaults.GetMatchingPolicies("sourceocisignaturepullsecrets", "Pod", "v1", map[string]string{"match": "match"}) checkGetMatches(t, c, err) if len(c) != 1 { t.Errorf("Wanted 1 match, got %d", len(c)) } checkSourceOCI(t, c[matchedPolicy].Authorities) if got := len(getAuthority(t, c, matchedPolicy).Sources[0].SignaturePullSecrets); got != 1 { t.Errorf("Did not get what I wanted %d, got %d", 1, got) } want = "examplePullSecret" if got := getAuthority(t, c, matchedPolicy).Sources[0].SignaturePullSecrets[0].Name; got != want { t.Errorf("Did not get what I wanted %q, got %+v", want, got) } // Test resource matching c, err = defaults.GetMatchingPolicies("match-pods", "Pod", "v1", map[string]string{"match": "match"}) checkGetMatches(t, c, err) if len(c) != 1 { t.Errorf("Wanted 1 match, got %d", len(c)) } c, err = defaults.GetMatchingPolicies("match-pods", "Pod", "apps/v1", map[string]string{"match": "match"}) if err != nil { t.Fatalf("GetMatchingPolicies() = %v", err) } if len(c) != 0 { t.Errorf("Wanted 0 matches, got %d", len(c)) } c, err = defaults.GetMatchingPolicies("match-pods", "Pod", "blah/v1alpha1", map[string]string{"match": "match"}) if err != nil { t.Fatalf("GetMatchingPolicies() = %v", err) } if len(c) != 0 { t.Errorf("Wanted 0 matches, got %d", len(c)) } } func TestFailsToLoadInvalid(t *testing.T) { wantErr := "failed to parse the entry \"cluster-image-policy-0\"" _, example := ConfigMapsFromTestFile(t, "config-invalid-image-policy") _, err := NewImagePoliciesConfigFromConfigMap(example) if err == nil { t.Error("Did not fail with invalid configmap") } else if !strings.Contains(err.Error(), wantErr) { t.Errorf("Unexpected error, wanted to contain %s : got %v", wantErr, err) } } func checkGetMatches(t *testing.T, c map[string]webhookcip.ClusterImagePolicy, err error) { t.Helper() if err != nil { t.Error("GetMatches Failed =", err) } if len(c) == 0 { t.Error("Wanted a config, got none.") } for _, v := range c { if v.Authorities != nil || len(v.Authorities) > 0 { return } } t.Error("Wanted a config and non-zero authorities, got no authorities") } func checkPublicKey(t *testing.T, gotKey crypto.PublicKey) { t.Helper() derBytes, err := x509.MarshalPKIXPublicKey(gotKey) if err != nil { t.Error("Failed to Marshal Key =", err) } pemBytes := pem.EncodeToMemory(&pem.Block{ Type: "PUBLIC KEY", Bytes: derBytes, }) // pem.EncodeToMemory has an extra newline at the end got := strings.TrimSuffix(string(pemBytes), "\n") if got != inlineKeyData { t.Errorf("Did not get what I wanted %s, got %s", inlineKeyData, string(pemBytes)) } } func checkSourceOCI(t *testing.T, authority []webhookcip.Authority) { t.Helper() if got := len(authority); got != 1 { t.Errorf("Did not get what I wanted %d, got %d", 1, got) } if got := len(authority[0].Sources); got != 1 { t.Errorf("Did not get what I wanted %d, got %d", 1, got) } want := len(authority[0].Sources) if got := len(authority[0].RemoteOpts); got != want { t.Errorf("Did not get what I wanted %d, got %d", want, got) } } func checkUIDAndResourceVersion(t *testing.T, cipName string, cip webhookcip.ClusterImagePolicy) { t.Helper() wantUID := fmt.Sprintf("%s-uid", cipName) if wantUID != string(cip.UID) { t.Errorf("UID mismatch want: %s got: %s", wantUID, cip.UID) } wantResourceVersion := fmt.Sprintf("%s-resource-version", cipName) if wantResourceVersion != cip.ResourceVersion { t.Errorf("UID mismatch want: %s got: %s", wantResourceVersion, cip.ResourceVersion) } } ================================================ FILE: pkg/apis/config/sigstore_keys.go ================================================ // // 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. package config import ( "context" "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rsa" "encoding/pem" "fmt" "github.com/sigstore/cosign/v3/pkg/cosign" "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" pbcommon "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" pbtrustroot "github.com/sigstore/protobuf-specs/gen/pb-go/trustroot/v1" "github.com/sigstore/sigstore/pkg/cryptoutils" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/types/known/timestamppb" corev1 "k8s.io/api/core/v1" "sigs.k8s.io/yaml" ) const ( // SigstoreKeysConfigName is the name of ConfigMap created by the // reconciler and consumed by the admission webhook for determining // which Keys/Certificates are trusted for things like Fulcio/Rekor, etc. SigstoreKeysConfigName = "config-sigstore-keys" ) // Type aliases for types from protobuf-specs. TODO: Consider just importing // the protobuf-specs types directly from each package as needed. // SigstoreKeys contains all the necessary Keys and Certificates for validating // against a specific instance of Sigstore. type SigstoreKeys = pbtrustroot.TrustedRoot type CertificateAuthority = pbtrustroot.CertificateAuthority type TransparencyLogInstance = pbtrustroot.TransparencyLogInstance type DistinguishedName = pbcommon.DistinguishedName type LogID = pbcommon.LogId type TimeRange = pbcommon.TimeRange type Timestamp = timestamppb.Timestamp type SigstoreKeysMap struct { SigstoreKeys map[string]*SigstoreKeys } // NewSigstoreKeysFromMap creates a map of SigstoreKeys to use for validation. func NewSigstoreKeysFromMap(data map[string]string) (*SigstoreKeysMap, error) { ret := make(map[string]*SigstoreKeys, len(data)) // Spin through the ConfigMap. Each entry will have a serialized form of // necessary validation keys in the form of SigstoreKeys. for k, v := range data { // This is the example that we use to document / test the ConfigMap. if k == "_example" { continue } if v == "" { return nil, fmt.Errorf("configmap has an entry %q but no value", k) } sigstoreKeys := &SigstoreKeys{} if err := parseSigstoreKeys(v, sigstoreKeys); err != nil { return nil, fmt.Errorf("failed to parse the entry %q : %q : %w", k, v, err) } ret[k] = sigstoreKeys } return &SigstoreKeysMap{SigstoreKeys: ret}, nil } // NewImagePoliciesConfigFromConfigMap creates a Features from the supplied ConfigMap func NewSigstoreKeysFromConfigMap(config *corev1.ConfigMap) (*SigstoreKeysMap, error) { return NewSigstoreKeysFromMap(config.Data) } func parseSigstoreKeys(entry string, out *pbtrustroot.TrustedRoot) error { j, err := yaml.YAMLToJSON([]byte(entry)) if err != nil { return fmt.Errorf("config's value could not be converted to JSON: %w : %s", err, entry) } return protojson.Unmarshal(j, out) } // ConvertSigstoreKeys takes a source and converts into a SigstoreKeys suitable // for serialization into a ConfigMap entry. func ConvertSigstoreKeys(_ context.Context, source *v1alpha1.SigstoreKeys) (sk *SigstoreKeys, err error) { sk = &SigstoreKeys{} sk.MediaType = "application/vnd.dev.sigstore.trustedroot+json;version=0.1" sk.CertificateAuthorities = make([]*pbtrustroot.CertificateAuthority, len(source.CertificateAuthorities)) for i := range source.CertificateAuthorities { sk.CertificateAuthorities[i], err = ConvertCertificateAuthority(source.CertificateAuthorities[i]) if err != nil { return nil, fmt.Errorf("failed to convert certificate authority: %w", err) } } sk.Tlogs = make([]*pbtrustroot.TransparencyLogInstance, len(source.TLogs)) for i := range source.TLogs { sk.Tlogs[i], err = ConvertTransparencyLogInstance(source.TLogs[i]) if err != nil { return nil, fmt.Errorf("failed to convert transparency log instance: %w", err) } } sk.Ctlogs = make([]*pbtrustroot.TransparencyLogInstance, len(source.CTLogs)) for i := range source.CTLogs { sk.Ctlogs[i], err = ConvertTransparencyLogInstance(source.CTLogs[i]) if err != nil { return nil, fmt.Errorf("failed to convert ct log instance: %w", err) } } sk.TimestampAuthorities = make([]*pbtrustroot.CertificateAuthority, len(source.TimeStampAuthorities)) for i := range source.TimeStampAuthorities { sk.TimestampAuthorities[i], err = ConvertCertificateAuthority(source.TimeStampAuthorities[i]) if err != nil { return nil, fmt.Errorf("failed to convert timestamp authority: %w", err) } } return sk, nil } // ConvertCertificateAuthority converts public into private CertificateAuthority func ConvertCertificateAuthority(source v1alpha1.CertificateAuthority) (*pbtrustroot.CertificateAuthority, error) { certChain, err := DeserializeCertChain(source.CertChain) if err != nil { return nil, err } return &pbtrustroot.CertificateAuthority{ Subject: &pbcommon.DistinguishedName{ Organization: source.Subject.Organization, CommonName: source.Subject.CommonName, }, Uri: source.URI.String(), CertChain: certChain, ValidFor: &pbcommon.TimeRange{ Start: ×tamppb.Timestamp{ Seconds: 0, // TODO: Add support for time range to v1alpha1.CertificateAuthority }, }, }, nil } // ConvertTransparencyLogInstance converts public into private // TransparencyLogInstance. func ConvertTransparencyLogInstance(source v1alpha1.TransparencyLogInstance) (*pbtrustroot.TransparencyLogInstance, error) { pbpk, pk, err := DeserializePublicKey(source.PublicKey) if err != nil { return nil, err } logID, err := cosign.GetTransparencyLogID(pk) if err != nil { return nil, err } return &pbtrustroot.TransparencyLogInstance{ BaseUrl: source.BaseURL.String(), HashAlgorithm: HashStringToHashAlgorithm(source.HashAlgorithm), PublicKey: pbpk, LogId: &pbcommon.LogId{ KeyId: []byte(logID), }, }, nil } func HashStringToHashAlgorithm(hash string) pbcommon.HashAlgorithm { switch hash { case "sha-256", "sha256": return pbcommon.HashAlgorithm_SHA2_256 case "sha-384", "sha384": return pbcommon.HashAlgorithm_SHA2_384 case "sha-512", "sha512": return pbcommon.HashAlgorithm_SHA2_512 default: return pbcommon.HashAlgorithm_HASH_ALGORITHM_UNSPECIFIED } } func SerializeCertChain(certChain *pbcommon.X509CertificateChain) []byte { var chain []byte for _, cert := range certChain.Certificates { bytes := cert.RawBytes block := &pem.Block{ Type: "CERTIFICATE", Bytes: bytes, } chain = append(chain, pem.EncodeToMemory(block)...) } return chain } func SerializePublicKey(publicKey *pbcommon.PublicKey) []byte { block := &pem.Block{ Type: "PUBLIC KEY", Bytes: publicKey.RawBytes, } return pem.EncodeToMemory(block) } func DeserializeCertChain(chain []byte) (*pbcommon.X509CertificateChain, error) { var certs []*pbcommon.X509Certificate var block *pem.Block for len(chain) > 0 { block, chain = pem.Decode(chain) if block == nil { return nil, fmt.Errorf("failed to decode certificate chain PEM") } certs = append(certs, &pbcommon.X509Certificate{RawBytes: block.Bytes}) } return &pbcommon.X509CertificateChain{Certificates: certs}, nil } func DeserializePublicKey(publicKey []byte) (*pbcommon.PublicKey, crypto.PublicKey, error) { block, _ := pem.Decode(publicKey) if block == nil { return nil, nil, fmt.Errorf("failed to decode public key") } pk, err := cryptoutils.UnmarshalPEMToPublicKey(publicKey) if err != nil { return nil, nil, fmt.Errorf("failed to unmarshal public key: %w", err) } var keyDetails pbcommon.PublicKeyDetails switch k := pk.(type) { case *ecdsa.PublicKey: switch k.Curve { case elliptic.P256(): keyDetails = pbcommon.PublicKeyDetails_PKIX_ECDSA_P256_SHA_256 case elliptic.P384(): keyDetails = pbcommon.PublicKeyDetails_PKIX_ECDSA_P384_SHA_384 case elliptic.P521(): keyDetails = pbcommon.PublicKeyDetails_PKIX_ECDSA_P521_SHA_512 default: keyDetails = pbcommon.PublicKeyDetails_PUBLIC_KEY_DETAILS_UNSPECIFIED } case *rsa.PublicKey: switch k.Size() { case 2048: keyDetails = pbcommon.PublicKeyDetails_PKIX_RSA_PSS_2048_SHA256 case 3072: keyDetails = pbcommon.PublicKeyDetails_PKIX_RSA_PSS_3072_SHA256 case 4096: keyDetails = pbcommon.PublicKeyDetails_PKIX_RSA_PSS_4096_SHA256 default: keyDetails = pbcommon.PublicKeyDetails_PUBLIC_KEY_DETAILS_UNSPECIFIED } default: keyDetails = pbcommon.PublicKeyDetails_PUBLIC_KEY_DETAILS_UNSPECIFIED } return &pbcommon.PublicKey{ RawBytes: block.Bytes, KeyDetails: keyDetails, ValidFor: &pbcommon.TimeRange{ Start: ×tamppb.Timestamp{ Seconds: 0, // TODO: Add support for time range to v1alpha.TransparencyLogInstance }, }, }, pk, nil } ================================================ FILE: pkg/apis/config/sigstore_keys_test.go ================================================ // 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. package config import ( "bytes" "encoding/pem" "testing" . "knative.dev/pkg/configmap/testing" _ "knative.dev/pkg/system/testing" ) const ( rekorPublicKey = `-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7D2WvgqSzs9jpdJsOJ5Nl6xg8JXm Nmo7M3bN7+dQddw9Ibc2R3SV8tzBZw0rST8FKcn4apJepcKM4qUpYUeNfw== -----END PUBLIC KEY----- ` tsaCertChain = `-----BEGIN CERTIFICATE----- MIIBzDCCAXKgAwIBAgIUfyGKDoFa7y6s/W1p1CiTmBRs1eAwCgYIKoZIzj0EAwIw MDEOMAwGA1UEChMFbG9jYWwxHjAcBgNVBAMTFVRlc3QgVFNBIEludGVybWVkaWF0 ZTAeFw0yMjExMDkyMDMxMzRaFw0zMTExMDkyMDM0MzRaMDAxDjAMBgNVBAoTBWxv Y2FsMR4wHAYDVQQDExVUZXN0IFRTQSBUaW1lc3RhbXBpbmcwWTATBgcqhkjOPQIB BggqhkjOPQMBBwNCAAR3KcDy9jwARX0rDvyr+MGGkG3n1OA0MU5+ZiDmgusFyk6U 6bovKWVMfD8J8NTcJZE0RaYJr8/dE9kgcIIXlhMwo2owaDAOBgNVHQ8BAf8EBAMC B4AwHQYDVR0OBBYEFHNn5R3b3MtUdSNrFO49Q6XDVSnkMB8GA1UdIwQYMBaAFNLS 6gno7Om++Qt5zIa+H9o0HiT2MBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMAoGCCqG SM49BAMCA0gAMEUCIQCF0olohnvdUq6T7/wPk19Z5aQP/yxRTjCWYuhn/TCyHgIg azV3air4GRZbN9bdYtcQ7JUAKq89GOhtFfl6kcoVUvU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIB0jCCAXigAwIBAgIUXpBmYJFFaGW3cC8p6b/DHr1i8IowCgYIKoZIzj0EAwIw KDEOMAwGA1UEChMFbG9jYWwxFjAUBgNVBAMTDVRlc3QgVFNBIFJvb3QwHhcNMjIx MTA5MjAyOTM0WhcNMzIxMTA5MjAzNDM0WjAwMQ4wDAYDVQQKEwVsb2NhbDEeMBwG A1UEAxMVVGVzdCBUU0EgSW50ZXJtZWRpYXRlMFkwEwYHKoZIzj0CAQYIKoZIzj0D AQcDQgAEKDPDRIwDS1ZCymub6yanCG5ma0qDjLpNonDvooSkRHEgU0TNibeJn6M+ 5W608hCw8nwuucMbXQ41kNeuBeevyqN4MHYwDgYDVR0PAQH/BAQDAgEGMBMGA1Ud JQQMMAoGCCsGAQUFBwMIMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNLS6gno 7Om++Qt5zIa+H9o0HiT2MB8GA1UdIwQYMBaAFB1nvXpNK7AuQlbJ+ya6nPSqWi+T MAoGCCqGSM49BAMCA0gAMEUCIGiwqCI29w7C4V8TltCsi728s5DtklCPySDASUSu a5y5AiEA40Ifdlwf7Uj8q8NSD6Z4g/0js0tGNdLSUJ1do/WoN0s= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIBlDCCATqgAwIBAgIUYZx9sS14En7SuHDOJJP4IPopMjUwCgYIKoZIzj0EAwIw KDEOMAwGA1UEChMFbG9jYWwxFjAUBgNVBAMTDVRlc3QgVFNBIFJvb3QwHhcNMjIx MTA5MjAyOTM0WhcNMzIxMTA5MjAzNDM0WjAoMQ4wDAYDVQQKEwVsb2NhbDEWMBQG A1UEAxMNVGVzdCBUU0EgUm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAbB B0SU8G75hVIUphChA4nfOwNWP347TjScIdsEPrKVn+/Y1HmmLHJDjSfn+xhEFoEk 7jqgrqon48i4xbo7xAujQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD AQH/MB0GA1UdDgQWBBQdZ716TSuwLkJWyfsmupz0qlovkzAKBggqhkjOPQQDAgNI ADBFAiBe5P56foqmFcZAVpEeAOFZrAlEiq05CCpMNYh5EjLvmAIhAKNF6xIV5uFd pSTJsAwzjW78CKQm7qol0uPmPPu6mNaw -----END CERTIFICATE-----` ) func TestDefaultsSigstoreKeysConfigurationFromFile(t *testing.T) { _, example := ConfigMapsFromTestFile(t, SigstoreKeysConfigName) keysMap, err := NewSigstoreKeysFromConfigMap(example) if err != nil { t.Error("NewSigstoreKeysFromConfigMap(example) =", err) } sigstoreKeys := keysMap.SigstoreKeys["my-custom-sigstore-keys"] org := sigstoreKeys.CertificateAuthorities[0].Subject.Organization if org != "fulcio-organization" { t.Errorf("Invalid organization, want foo got %s", org) } // TODO: Validate the entire file, above spot checks are not enough, but // at least we can unmarshal. // Note that even though sigstoreKeys.TLog[0].PublicKey is base64 encoded // in the ConfigMap it gets decoded when we fetch it above, so we get the // PEM format for it directly. Same for tsaCertChain got := sigstoreKeys.Tlogs[0].PublicKey.RawBytes block, _ := pem.Decode([]byte(rekorPublicKey)) if !bytes.Equal(got, block.Bytes) { t.Errorf("Invalid public key, want %s got %s", block.Bytes, got) } certs := []byte(tsaCertChain) for _, cert := range sigstoreKeys.TimestampAuthorities[0].CertChain.Certificates { block, certs = pem.Decode(certs) if !bytes.Equal(block.Bytes, cert.RawBytes) { t.Errorf("Invalid cert chain, want %s got %s", cert.RawBytes, block.Bytes) } } } ================================================ FILE: pkg/apis/config/store.go ================================================ // // 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. package config import ( "context" "knative.dev/pkg/configmap" ) type cfgKey struct{} // Config holds the collection of configurations that we attach to contexts. // +k8s:deepcopy-gen=false type Config struct { ImagePolicyConfig *ImagePolicyConfig SigstoreKeysConfig *SigstoreKeysMap } // FromContext extracts a Config from the provided context. func FromContext(ctx context.Context) *Config { x, ok := ctx.Value(cfgKey{}).(*Config) if ok { return x } return nil } // FromContextOrDefaults is like FromContext, but when no Config is attached it // returns a Config populated with the defaults for each of the Config fields. func FromContextOrDefaults(ctx context.Context) *Config { if cfg := FromContext(ctx); cfg != nil { return cfg } config, _ := NewImagePoliciesConfigFromMap(map[string]string{}) sigstoreKeysMap, _ := NewSigstoreKeysFromMap(map[string]string{}) return &Config{ ImagePolicyConfig: config, SigstoreKeysConfig: sigstoreKeysMap, } } // ToContext attaches the provided Config to the provided context, returning the // new context with the Config attached. func ToContext(ctx context.Context, c *Config) context.Context { return context.WithValue(ctx, cfgKey{}, c) } // Store is a typed wrapper around configmap.Untyped store to handle our configmaps. // +k8s:deepcopy-gen=false type Store struct { *configmap.UntypedStore } // NewStore creates a new store of Configs and optionally calls functions when ConfigMaps are updated. func NewStore(logger configmap.Logger, onAfterStore ...func(name string, value interface{})) *Store { store := &Store{ UntypedStore: configmap.NewUntypedStore( "image-policies", logger, configmap.Constructors{ ImagePoliciesConfigName: NewImagePoliciesConfigFromConfigMap, SigstoreKeysConfigName: NewSigstoreKeysFromConfigMap, }, onAfterStore..., ), } return store } // ToContext attaches the current Config state to the provided context. func (s *Store) ToContext(ctx context.Context) context.Context { return ToContext(ctx, s.Load()) } // Load creates a Config from the current config state of the Store. func (s *Store) Load() *Config { return &Config{ ImagePolicyConfig: s.UntypedLoad(ImagePoliciesConfigName).(*ImagePolicyConfig), SigstoreKeysConfig: s.UntypedLoad(SigstoreKeysConfigName).(*SigstoreKeysMap), } } ================================================ FILE: pkg/apis/config/store_test.go ================================================ // 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. package config import ( "context" "testing" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/sigstore/cosign/v3/pkg/oci/remote" "google.golang.org/protobuf/testing/protocmp" "k8s.io/apimachinery/pkg/api/resource" logtesting "knative.dev/pkg/logging/testing" . "knative.dev/pkg/configmap/testing" ) var ignoreStuff = cmp.Options{ protocmp.Transform(), cmpopts.IgnoreUnexported(resource.Quantity{}), // Ignore functional remote options cmpopts.IgnoreTypes((remote.Option)(nil)), } func TestStoreLoadWithContext(t *testing.T) { store := NewStore(logtesting.TestLogger(t)) _, imagePolicies := ConfigMapsFromTestFile(t, ImagePoliciesConfigName) _, sigstoreKeysMap := ConfigMapsFromTestFile(t, SigstoreKeysConfigName) store.OnConfigChanged(imagePolicies) store.OnConfigChanged(sigstoreKeysMap) config := FromContextOrDefaults(store.ToContext(context.Background())) t.Run("image-policies", func(t *testing.T) { expected, _ := NewImagePoliciesConfigFromConfigMap(imagePolicies) if diff := cmp.Diff(expected, config.ImagePolicyConfig, ignoreStuff...); diff != "" { t.Error("Unexpected defaults config (-want, +got):", diff) } }) t.Run("sigstore-keys", func(t *testing.T) { expected, _ := NewSigstoreKeysFromConfigMap(sigstoreKeysMap) if diff := cmp.Diff(expected, config.SigstoreKeysConfig, ignoreStuff...); diff != "" { t.Error("Unexpected defaults config (-want, +got):", diff) } }) } func TestStoreLoadWithContextOrDefaults(t *testing.T) { imagePolicies := ConfigMapFromTestFile(t, ImagePoliciesConfigName) sigstoreKeysMap := ConfigMapFromTestFile(t, SigstoreKeysConfigName) config := FromContextOrDefaults(context.Background()) t.Run("image-policies", func(t *testing.T) { expected, _ := NewImagePoliciesConfigFromConfigMap(imagePolicies) if diff := cmp.Diff(expected, config.ImagePolicyConfig, ignoreStuff...); diff != "" { t.Error("Unexpected defaults config (-want, +got):", diff) } }) t.Run("sigstore-keys", func(t *testing.T) { expected, _ := NewSigstoreKeysFromConfigMap(sigstoreKeysMap) if diff := cmp.Diff(expected, config.SigstoreKeysConfig, ignoreStuff...); diff != "" { t.Error("Unexpected defaults config (-want, +got):", diff) } }) } ================================================ FILE: pkg/apis/config/testdata/config-image-policies.yaml ================================================ # 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. apiVersion: v1 kind: ConfigMap metadata: name: config-image-policies namespace: cosign-system labels: policy.sigstore.dev/release: devel data: _example: | ################################ # # # EXAMPLE CONFIGURATION # # # ################################ cluster-image-policy-0: | uid: cluster-image-policy-0-uid resourceVersion: cluster-image-policy-0-resource-version images: - glob: rando authorities: - name: attestation-0 key: data: |- -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J RCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ== -----END PUBLIC KEY----- - name: attestation-1 key: kms: whatevs cluster-image-policy-1: | uid: cluster-image-policy-1-uid resourceVersion: cluster-image-policy-1-resource-version images: - glob: randomstuff* authorities: - name: attestation-0 key: data: |- -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J RCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ== -----END PUBLIC KEY----- cluster-image-policy-2: | uid: cluster-image-policy-2-uid resourceVersion: cluster-image-policy-2-resource-version images: - glob: rando3 authorities: - name: attestation-0 rfc3161timestamp: trustRootRef: trustroot-tsa-ref keyless: insecureIgnoreSCT: true ca-cert: data: |- -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J RCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ== -----END PUBLIC KEY----- url: http://keylessurl.here identities: - issuer: issuer subject: subject cluster-image-policy-3: | uid: cluster-image-policy-3-uid resourceVersion: cluster-image-policy-3-resource-version images: - glob: inlinecert authorities: - name: attestation-0 key: data: |- -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J RCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ== -----END PUBLIC KEY----- cluster-image-policy-4: | uid: cluster-image-policy-4-uid resourceVersion: cluster-image-policy-4-resource-version images: - glob: regexstring* authorities: - name: attestation-0 key: data: |- -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J RCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ== -----END PUBLIC KEY----- cluster-image-policy-5: | uid: cluster-image-policy-5-uid resourceVersion: cluster-image-policy-5-resource-version images: - glob: regexstringtoo* authorities: - name: attestation-0 key: data: |- -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J RCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ== -----END PUBLIC KEY----- cluster-image-policy-json: "{\"images\":[{\"glob\":\"ghcr.io/example/*\",\"regex\":\"\"}],\"authorities\":[{\"key\":{\"data\":\"-----BEGIN PUBLIC KEY-----\\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J\\nRCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ==\\n-----END PUBLIC KEY-----\"}}]}" cluster-image-policy-with-policy-attestations: | images: - glob: withattestations authorities: - name: attestation-0 keyless: ca-cert: data: |- -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J RCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ== -----END PUBLIC KEY----- url: http://keylessurl.here identities: - issuer: issuer subject: subject attestations: - predicateType: vuln type: cue data: "test-cue-here" policy: type: cue data: "cip level cue here" cluster-image-policy-source-oci: | images: - glob: sourceocionly* authorities: - name: attestation-0 key: data: |- -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J RCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ== -----END PUBLIC KEY----- source: - oci: "example.registry.com/alternative/signature" cluster-image-policy-source-oci-signature-pull-secrets: | images: - glob: sourceocisignaturepullsecrets* authorities: - name: attestation-0 key: data: |- -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J RCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ== -----END PUBLIC KEY----- source: - oci: "example.registry.com/alternative/signature" signaturePullSecrets: - name: examplePullSecret cluster-image-policy-match-pods: | match: - version: v1 resource: pods images: - glob: match-pods* authorities: - name: attestation-0 key: data: |- -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J RCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ== -----END PUBLIC KEY----- cluster-image-policy-match-deployments: | match: - group: apps version: v1 resource: deployments images: - glob: match-deployments* authorities: - name: attestation-0 key: data: |- -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J RCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ== -----END PUBLIC KEY----- ================================================ FILE: pkg/apis/config/testdata/config-invalid-image-policy.yaml ================================================ # 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. apiVersion: v1 kind: ConfigMap metadata: name: config-image-policies namespace: cosign-system labels: policy.sigstore.dev/release: devel data: _example: | ################################ # # # EXAMPLE CONFIGURATION # # # ################################ cluster-image-policy-0: | images: - glob: invalidkey authorities: - name: attestation-0 key: data: |- -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzINVALIDKEYHEREAExB6+H6054/W1SJgs5JR6AJr6J35J RCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ== -----END PUBLIC KEY----- ================================================ FILE: pkg/apis/config/testdata/config-sigstore-keys.yaml ================================================ # 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. apiVersion: v1 kind: ConfigMap metadata: name: config-sigstore-keys namespace: cosign-system labels: policy.sigstore.dev/release: devel data: _example: | ################################ # # # EXAMPLE CONFIGURATION # # # ################################ my-custom-sigstore-keys: |- {"certificateAuthorities":[{"subject":{"organization":"fulcio-organization","commonName":"fulcio-common-name"},"uri":"https://fulcio.example.com","certChain":{"certificates":[{"rawBytes":"MIIFwzCCA6ugAwIBAgIIK7xb+rqY4gEwDQYJKoZIhvcNAQELBQAwfjEMMAoGA1UEBhMDVVNBMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRYwFAYDVQQJEw01NDggTWFya2V0IFN0MQ4wDAYDVQQREwU1NzI3NDEZMBcGA1UEChMQTGludXggRm91bmRhdGlvbjAeFw0yMjEyMDgwMjE3NTFaFw0yMzEyMDgwMjE3NTFaMH4xDDAKBgNVBAYTA1VTQTETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEWMBQGA1UECRMNNTQ4IE1hcmtldCBTdDEOMAwGA1UEERMFNTcyNzQxGTAXBgNVBAoTEExpbnV4IEZvdW5kYXRpb24wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC142Ejlg2QxIwpNjbaeW/ft9sH1TXU6CWgbsvVp77vRgckSnpM3RTC/gwEwJHtX+GOTrP9ro6nFJN3G3hcFnaMHLKdGrof9iHu/w/lZLwQzXzVT+0ZyZxytHAWGFBvmYM4J33jH6Dj9PvqONwtSBSmZBPc/H/8EvYsUzxPWukhOtotSH3VXDqZ4jl96MLe0+5g2Wi7MxRX44X1RiPS14ba1ES538bThhcQ4SMj3uhbdsCIkcm7eF4EY3pEXQpXEEGnZGfwYgQr+6cT07Zd/WDM0NX3KxH6qRk9gDjPnfcMuFbOTbfD/nuvx6FNX6OUrzrZSglkLvcPIBVOW7Ln41LAb7aXmbWLFEJnuLooPpYYr+6NhnFDNGpsBKGKr/kvbQyDKKst3CKj9otPS1363ni41qnoA7YWSqxwz4185dKKc+Y7yvJQsRlr6qG1sNLO+c77fSS5VZImzNozBcRkuLJFlX+WB0uzgQU5s45IZW+fK92nfu8MmKjzHR+idyr4OyjS0YSN3GMgc0UP7K6hVphLedApFpykBSFGUgiPZwrT+mGSVgmOXq5n1dQTCD14lEh2qt3/rff8zNc0CMANWybaMGBGQ4bhVVXeRKYx9u2PZjPv53p7Yb/DCdqnGEDw/HCBDiCs4oYe4daE36xUojxDSm3DaeNG68z9RL7gfUjAxQIDAQABo0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQUf+lbNX0Wh4h+Q0SRthRK+KfLjqEwDQYJKoZIhvcNAQELBQADggIBAEhJja0ZSKwXcaOXCYRXTE06+JbpezI5LevBhmbRQK789Rq10JeAXa7mEToRGlGFLH2uDT11msFKyM3v67KlE1SYVcqKmClYfIVEYH3La0uI+9rHZnWgb4Bly1B8wblKJzhYQD9Z4H/gs+BAsoRX5VoFyIgkNBk1p3ftaVCbkQvS0OYtYs5iw4eKcI71/IsTIT3Zppj9R8IGsqwLKgzfnyNcFJdz+ohc6V22PjZMEBHCsHPO4av2LlWK5Y1flL+2bqTqbmO/bjfX0w4Z1DuojRcOZF7SH4O3Qu2Y7/69gH7Cp0niVCm5z+S5011V6PvMjrmiE+xVkxLHbYEgocbFhd5DciMCXpvsuDZojaI3FREmBqiIhKoki3rbwuElya78bMwkZ1krp76nWso47/0+51io/WriAdr0cjmzonho7RqIE3DC77CEMkagZvKSmL3sff+WNSrnPlznK19NA2z4ImW9MszqPrCTQGP//BBu7SamzofVM9f4PAIrFTpnW6sGdpCzP8E0WUu9B+viKrtfM/9sxnI9WhfJPdrEP0iZW3vhwvgQbKb5D2OSU4nrVov6BWr/BnhQK8IXo1tq3j8FCRIoleXNhks4gnkOaDsW2KtVqwtK3iO3BvPbL5w0gdLjwMLkek72y61Xqz5WxZwNhl5YcmBKuSvmVSHvA68BVSbB"}]},"validFor":{"start":"2024-01-01T00:00:00Z"}}],"tlogs":[{"baseUrl":"https://rekor.example.com","hashAlgorithm":"SHA2_256","publicKey":{"rawBytes":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7D2WvgqSzs9jpdJsOJ5Nl6xg8JXmNmo7M3bN7+dQddw9Ibc2R3SV8tzBZw0rST8FKcn4apJepcKM4qUpYUeNfw==","keyDetails":"PKIX_ECDSA_P256_SHA_256","validFor":{"start":"2024-01-01T00:00:00Z"}},"logId":{"keyId":"0bac0fddd0c15fbc46f8b1bf51c2b57676a9f262294fe13417d85602e73f392a"}}],"ctlogs":[{"baseUrl":"https://ctfe.example.com","hashAlgorithm":"SHA2_256","publicKey":{"rawBytes":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJvCJi707fv5tMJ1U2TVMZ+uO4dKGaEcvjlCkgBCKXbrkumZV0m0dSlK1V1gxEiyQ8y6hk1MxJNe2AZrZUt7a4w==","keyDetails":"PKIX_ECDSA_P256_SHA_256","validFor":{"start":"2024-01-01T00:00:00Z"}},"logId":{"keyId":"39d1c085f7d5f3fe7a0de9e52a3ead14186891e52a9269d90de7990a30b55083"}}],"timestampAuthorities":[{"subject":{"organization":"tsa-organization","commonName":"tsa-common-name"},"uri":"https://tsa.example.com","certChain":{"certificates":[{"rawBytes":"MIIBzDCCAXKgAwIBAgIUfyGKDoFa7y6s/W1p1CiTmBRs1eAwCgYIKoZIzj0EAwIwMDEOMAwGA1UEChMFbG9jYWwxHjAcBgNVBAMTFVRlc3QgVFNBIEludGVybWVkaWF0ZTAeFw0yMjExMDkyMDMxMzRaFw0zMTExMDkyMDM0MzRaMDAxDjAMBgNVBAoTBWxvY2FsMR4wHAYDVQQDExVUZXN0IFRTQSBUaW1lc3RhbXBpbmcwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAR3KcDy9jwARX0rDvyr+MGGkG3n1OA0MU5+ZiDmgusFyk6U6bovKWVMfD8J8NTcJZE0RaYJr8/dE9kgcIIXlhMwo2owaDAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFHNn5R3b3MtUdSNrFO49Q6XDVSnkMB8GA1UdIwQYMBaAFNLS6gno7Om++Qt5zIa+H9o0HiT2MBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMAoGCCqGSM49BAMCA0gAMEUCIQCF0olohnvdUq6T7/wPk19Z5aQP/yxRTjCWYuhn/TCyHgIgazV3air4GRZbN9bdYtcQ7JUAKq89GOhtFfl6kcoVUvU="},{"rawBytes":"MIIB0jCCAXigAwIBAgIUXpBmYJFFaGW3cC8p6b/DHr1i8IowCgYIKoZIzj0EAwIwKDEOMAwGA1UEChMFbG9jYWwxFjAUBgNVBAMTDVRlc3QgVFNBIFJvb3QwHhcNMjIxMTA5MjAyOTM0WhcNMzIxMTA5MjAzNDM0WjAwMQ4wDAYDVQQKEwVsb2NhbDEeMBwGA1UEAxMVVGVzdCBUU0EgSW50ZXJtZWRpYXRlMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEKDPDRIwDS1ZCymub6yanCG5ma0qDjLpNonDvooSkRHEgU0TNibeJn6M+5W608hCw8nwuucMbXQ41kNeuBeevyqN4MHYwDgYDVR0PAQH/BAQDAgEGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNLS6gno7Om++Qt5zIa+H9o0HiT2MB8GA1UdIwQYMBaAFB1nvXpNK7AuQlbJ+ya6nPSqWi+TMAoGCCqGSM49BAMCA0gAMEUCIGiwqCI29w7C4V8TltCsi728s5DtklCPySDASUSua5y5AiEA40Ifdlwf7Uj8q8NSD6Z4g/0js0tGNdLSUJ1do/WoN0s="},{"rawBytes":"MIIBlDCCATqgAwIBAgIUYZx9sS14En7SuHDOJJP4IPopMjUwCgYIKoZIzj0EAwIwKDEOMAwGA1UEChMFbG9jYWwxFjAUBgNVBAMTDVRlc3QgVFNBIFJvb3QwHhcNMjIxMTA5MjAyOTM0WhcNMzIxMTA5MjAzNDM0WjAoMQ4wDAYDVQQKEwVsb2NhbDEWMBQGA1UEAxMNVGVzdCBUU0EgUm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAbBB0SU8G75hVIUphChA4nfOwNWP347TjScIdsEPrKVn+/Y1HmmLHJDjSfn+xhEFoEk7jqgrqon48i4xbo7xAujQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQdZ716TSuwLkJWyfsmupz0qlovkzAKBggqhkjOPQQDAgNIADBFAiBe5P56foqmFcZAVpEeAOFZrAlEiq05CCpMNYh5EjLvmAIhAKNF6xIV5uFdpSTJsAwzjW78CKQm7qol0uPmPPu6mNaw"}]},"validFor":{"start":"2024-01-01T00:00:00Z"}}]} ================================================ FILE: pkg/apis/duck/v1beta1/doc.go ================================================ // // 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. // Package v1beta1 contains the Autoscaling v1alpha1 API types. // +k8s:deepcopy-gen=package // +groupName=duck.sigstore.policy.dev package v1beta1 ================================================ FILE: pkg/apis/duck/v1beta1/podscalable_defaults.go ================================================ // // 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. package v1beta1 import ( "context" ) // PodScalableDefaulter is a callback to validate a PodScalable. type PodScalableDefaulter func(context.Context, *PodScalable) // SetDefaults implements apis.Defaultable func (ps *PodScalable) SetDefaults(ctx context.Context) { if psd := GetPodScalableDefaulter(ctx); psd != nil { psd(ctx, ps) } } // psdKey is used for associating a PodScalableDefaulter with a context.Context type psdKey struct{} func WithPodScalableDefaulter(ctx context.Context, psd PodScalableDefaulter) context.Context { return context.WithValue(ctx, psdKey{}, psd) } // GetPodScalableDefaulter extracts the PodScalableDefaulter from the context. func GetPodScalableDefaulter(ctx context.Context) PodScalableDefaulter { untyped := ctx.Value(psdKey{}) if untyped == nil { return nil } return untyped.(PodScalableDefaulter) } ================================================ FILE: pkg/apis/duck/v1beta1/podscalable_defaults_test.go ================================================ // // 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. package v1beta1 import ( "context" "strings" "testing" "github.com/google/go-cmp/cmp" corev1 "k8s.io/api/core/v1" "knative.dev/pkg/ptr" ) func TestPodScalableDefaulting(t *testing.T) { p := PodScalable{ Spec: PodScalableSpec{ Replicas: ptr.Int32(10), Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ Containers: []corev1.Container{{ Name: "blah", Image: "busybox", }}, }, }, }, } tests := []struct { name string with func(context.Context) context.Context want *PodScalable }{{ name: "no check", with: func(ctx context.Context) context.Context { return ctx }, want: p.DeepCopy(), }, { name: "no change", with: func(ctx context.Context) context.Context { return WithPodScalableDefaulter(ctx, func(_ context.Context, _ *PodScalable) { }) }, want: p.DeepCopy(), }, { name: "no busybox", with: func(ctx context.Context) context.Context { return WithPodScalableDefaulter(ctx, func(_ context.Context, wp *PodScalable) { for i, c := range wp.Spec.Template.Spec.InitContainers { if !strings.Contains(c.Image, "@") { wp.Spec.Template.Spec.InitContainers[i].Image = c.Image + "@sha256:deadbeef" } } for i, c := range wp.Spec.Template.Spec.Containers { if !strings.Contains(c.Image, "@") { wp.Spec.Template.Spec.Containers[i].Image = c.Image + "@sha256:deadbeef" } } }) }, want: &PodScalable{ Spec: PodScalableSpec{ Replicas: ptr.Int32(10), Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ Containers: []corev1.Container{{ Name: "blah", Image: "busybox@sha256:deadbeef", }}, }, }, }, }, }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { ctx := test.with(context.Background()) got := p.DeepCopy() got.SetDefaults(ctx) if !cmp.Equal(test.want, got) { t.Errorf("SetDefaults (-want, +got) = %s", cmp.Diff(test.want, got)) } }) } } ================================================ FILE: pkg/apis/duck/v1beta1/podscalable_implements_test.go ================================================ // // 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. package v1beta1 import ( "testing" appsv1 "k8s.io/api/apps/v1" "knative.dev/pkg/apis/duck" ) func TestImplementsPodScalable(t *testing.T) { instances := []interface{}{ &PodScalable{}, &appsv1.ReplicaSet{}, &appsv1.Deployment{}, &appsv1.StatefulSet{}, } for _, instance := range instances { if err := duck.VerifyType(instance, &PodScalable{}); err != nil { t.Error(err) } } } ================================================ FILE: pkg/apis/duck/v1beta1/podscalable_types.go ================================================ // // 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. package v1beta1 import ( "context" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "knative.dev/pkg/apis" "knative.dev/pkg/apis/duck" "knative.dev/pkg/ptr" ) // +genduck // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // PodScalable is a duck type that the are PodSpecable but also can scale. // These are used to validate resources that can be modified to scale down // even if they contain invalid images. type PodScalable struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` Spec PodScalableSpec `json:"spec"` Status PodScalableStatus `json:"status"` } // PodScalableSpec is the specification for the desired state of a // PodScalable (or at least our shared portion). type PodScalableSpec struct { Replicas *int32 `json:"replicas,omitempty"` Selector *metav1.LabelSelector `json:"selector"` Template corev1.PodTemplateSpec `json:"template"` } // PodScalableStatus is the observed state of a PodScalable (or at // least our shared portion). type PodScalableStatus struct { Replicas int32 `json:"replicas,omitempty"` } var ( _ apis.Validatable = (*PodScalable)(nil) _ duck.Populatable = (*PodScalable)(nil) _ duck.Implementable = (*PodScalable)(nil) _ apis.Listable = (*PodScalable)(nil) ) // GetFullType implements duck.Implementable func (*PodScalable) GetFullType() duck.Populatable { return &PodScalable{} } // Populate implements duck.Populatable func (ps *PodScalable) Populate() { ps.Spec = PodScalableSpec{ Replicas: ptr.Int32(12), Selector: &metav1.LabelSelector{ MatchLabels: map[string]string{ "foo": "bar", }, MatchExpressions: []metav1.LabelSelectorRequirement{{ Key: "foo", Operator: "In", Values: []string{"baz", "blah"}, }}, }, Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ Labels: map[string]string{ "foo": "bar", }, }, Spec: corev1.PodSpec{ Containers: []corev1.Container{{ Name: "container-name", Image: "container-image:latest", }}, }, }, } ps.Status = PodScalableStatus{ Replicas: 42, } } // GetListType implements apis.Listable func (*PodScalable) GetListType() runtime.Object { return &PodScalableList{} } // IsScalingDown returns true if PodScalable is being scaled down func (ps *PodScalable) IsScalingDown(ctx context.Context) bool { if apis.IsInUpdate(ctx) { newReplicaCount := ps.Spec.Replicas original := apis.GetBaseline(ctx).(*PodScalable) if newReplicaCount != nil && original != nil && original.Spec.Replicas != nil { if *newReplicaCount < *original.Spec.Replicas { return true } } } return false } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // PodScalableList is a list of PodScalable resources type PodScalableList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata"` Items []PodScalable `json:"items"` } ================================================ FILE: pkg/apis/duck/v1beta1/podscalable_types_test.go ================================================ // // 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. package v1beta1 import ( "context" "testing" corev1 "k8s.io/api/core/v1" "knative.dev/pkg/apis" "knative.dev/pkg/ptr" ) func TestPodScalableIsScalingDown(t *testing.T) { original := &PodScalable{ Spec: PodScalableSpec{ Replicas: ptr.Int32(2), Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ Containers: []corev1.Container{{ Name: "blah", Image: "busybox", }}, }, }, }, } tests := []struct { name string new *PodScalable with func(context.Context) context.Context want bool }{{ name: "not in update", new: original.DeepCopy(), want: false, }, { name: "scaling up", new: &PodScalable{ Spec: PodScalableSpec{ Replicas: ptr.Int32(4), }}, want: false, with: func(ctx context.Context) context.Context { return apis.WithinUpdate(ctx, original) }, }, { name: "scaling down", new: &PodScalable{ Spec: PodScalableSpec{ Replicas: ptr.Int32(1), }}, want: true, with: func(ctx context.Context) context.Context { return apis.WithinUpdate(ctx, original) }, }, { name: "scaling down with /scale", new: &PodScalable{ Spec: PodScalableSpec{ Replicas: ptr.Int32(1), }}, want: true, with: func(ctx context.Context) context.Context { return apis.WithinSubResourceUpdate(ctx, original, "scale") }, }} for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { ctx := context.Background() if tc.with != nil { ctx = tc.with(ctx) } if got := tc.new.IsScalingDown(ctx); tc.want != got { t.Errorf("Unexpected scaling down result, want %v got %v", tc.want, got) } }) } } ================================================ FILE: pkg/apis/duck/v1beta1/podscalable_validation.go ================================================ // // 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. package v1beta1 import ( "context" "knative.dev/pkg/apis" ) // PodScalableValidator is a callback to validate a PodScalable. type PodScalableValidator func(context.Context, *PodScalable) *apis.FieldError // Validate implements apis.Validatable func (ps *PodScalable) Validate(ctx context.Context) *apis.FieldError { if psv := GetPodScalableValidator(ctx); psv != nil { return psv(ctx, ps) } return nil } // psvKey is used for associating a PodScalableValidator with a context.Context type psvKey struct{} func WithPodScalableValidator(ctx context.Context, psv PodScalableValidator) context.Context { return context.WithValue(ctx, psvKey{}, psv) } // GetPodScalableValidator extracts the PodSpecValidator from the context. func GetPodScalableValidator(ctx context.Context) PodScalableValidator { untyped := ctx.Value(psvKey{}) if untyped == nil { return nil } return untyped.(PodScalableValidator) } ================================================ FILE: pkg/apis/duck/v1beta1/podscalable_validation_test.go ================================================ // // 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. package v1beta1 import ( "context" "testing" corev1 "k8s.io/api/core/v1" "knative.dev/pkg/apis" "knative.dev/pkg/ptr" ) func TestPodScalableValidation(t *testing.T) { tests := []struct { name string with func(context.Context) context.Context want *apis.FieldError }{{ name: "no check", with: func(ctx context.Context) context.Context { return ctx }, want: nil, }, { name: "no error", with: func(ctx context.Context) context.Context { return WithPodScalableValidator(ctx, func(_ context.Context, _ *PodScalable) *apis.FieldError { return nil }) }, want: nil, }, { name: "no busybox", with: func(ctx context.Context) context.Context { return WithPodScalableValidator(ctx, func(_ context.Context, wp *PodScalable) *apis.FieldError { for i, c := range wp.Spec.Template.Spec.InitContainers { if c.Image == "busybox" { return apis.ErrInvalidValue(c.Image, "image").ViaFieldIndex("spec.template.spec.initContainers", i) } } for i, c := range wp.Spec.Template.Spec.Containers { if c.Image == "busybox" { return apis.ErrInvalidValue(c.Image, "image").ViaFieldIndex("spec.template.spec.containers", i) } } return nil }) }, want: apis.ErrInvalidValue("busybox", "spec.template.spec.containers[0].image"), }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { p := PodScalable{ Spec: PodScalableSpec{ Replicas: ptr.Int32(3), Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ Containers: []corev1.Container{{ Name: "blah", Image: "busybox", }}, }, }, }, } ctx := test.with(context.Background()) got := p.Validate(ctx) if test.want.Error() != got.Error() { t.Errorf("Validate() = %v, wanted %v", got, test.want) } }) } } ================================================ FILE: pkg/apis/duck/v1beta1/register.go ================================================ // // 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. // Package v1beta1 contains the Autoscaling v1alpha1 API types. package v1beta1 import ( "github.com/sigstore/policy-controller/pkg/apis/policy" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" ) // SchemeGroupVersion is group version used to register these objects var SchemeGroupVersion = schema.GroupVersion{Group: policy.DuckGroupName, Version: "v1beta1"} // Kind takes an unqualified kind and returns back a Group qualified GroupKind func Kind(kind string) schema.GroupKind { return SchemeGroupVersion.WithKind(kind).GroupKind() } // Resource takes an unqualified resource and returns a Group qualified GroupResource func Resource(resource string) schema.GroupResource { return SchemeGroupVersion.WithResource(resource).GroupResource() } var ( // SchemeBuilder registers the addKnownTypes function. SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) // AddToScheme applies all the stored functions to the scheme. AddToScheme = SchemeBuilder.AddToScheme ) // Adds the list of known types to Scheme. func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &PodScalable{}, &PodScalableList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil } ================================================ FILE: pkg/apis/duck/v1beta1/zz_generated.deepcopy.go ================================================ //go:build !ignore_autogenerated // +build !ignore_autogenerated // 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. // Code generated by deepcopy-gen. DO NOT EDIT. package v1beta1 import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PodScalable) DeepCopyInto(out *PodScalable) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) out.Status = in.Status return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodScalable. func (in *PodScalable) DeepCopy() *PodScalable { if in == nil { return nil } out := new(PodScalable) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. func (in *PodScalable) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } return nil } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PodScalableList) DeepCopyInto(out *PodScalableList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items *out = make([]PodScalable, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodScalableList. func (in *PodScalableList) DeepCopy() *PodScalableList { if in == nil { return nil } out := new(PodScalableList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. func (in *PodScalableList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } return nil } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PodScalableSpec) DeepCopyInto(out *PodScalableSpec) { *out = *in if in.Replicas != nil { in, out := &in.Replicas, &out.Replicas *out = new(int32) **out = **in } if in.Selector != nil { in, out := &in.Selector, &out.Selector *out = new(v1.LabelSelector) (*in).DeepCopyInto(*out) } in.Template.DeepCopyInto(&out.Template) return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodScalableSpec. func (in *PodScalableSpec) DeepCopy() *PodScalableSpec { if in == nil { return nil } out := new(PodScalableSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PodScalableStatus) DeepCopyInto(out *PodScalableStatus) { *out = *in return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodScalableStatus. func (in *PodScalableStatus) DeepCopy() *PodScalableStatus { if in == nil { return nil } out := new(PodScalableStatus) in.DeepCopyInto(out) return out } ================================================ FILE: pkg/apis/glob/glob.go ================================================ // // 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. package glob import ( "fmt" "regexp" "strings" "github.com/google/go-containerregistry/pkg/name" ) const ( ResolvedDockerhubHost = "index.docker.io/" // Images such as "busybox" reside in the dockerhub "library" repository // The full resolved image reference would be index.docker.io/library/busybox DockerhubPublicRepository = "library/" ) var validGlob = regexp.MustCompile(`^[a-zA-Z0-9-_:\/\*\.@]+$`) // Compile attempts to normalize the glob and turn it into a regular expression // that we can use for matching image names. func Compile(glob string) (*regexp.Regexp, error) { if glob == "*/*" { // TODO: Warn that the glob match "*/*" should be "index.docker.io/*/*". glob = "index.docker.io/*/*" } if glob == "*" { // TODO: Warn that the glob match "*" should be "index.docker.io/library/*". glob = "index.docker.io/library/*" } // Reject that glob doesn't look like a regexp if !validGlob.MatchString(glob) { return nil, fmt.Errorf("invalid glob %q", glob) } // Translate glob to regexp. glob = strings.ReplaceAll(glob, ".", `\.`) // . in glob means \. in regexp glob = strings.ReplaceAll(glob, "**", "#") // ** in glob means 0+ of any character in regexp // We replace ** with a placeholder here, rather than `.*` directly, because the next line // would replace that `*` again, breaking the regexp. So we stash the change with a placeholder, // then replace the placeholder later to preserve the original intent. glob = strings.ReplaceAll(glob, "*", "[^/]*") // * in glob means 0+ of any non-`/` character in regexp glob = strings.ReplaceAll(glob, "#", ".*") glob = fmt.Sprintf("^%s$", glob) // glob must match the whole string return regexp.Compile(glob) } // Match will return true if the image reference matches the requested glob pattern. // // If the image reference is invalid, an error will be returned. // // In the glob pattern, the "*" character matches any non-"/" character, and "**" matches any character, including "/". // // If the image is a DockerHub official image like "ubuntu" or "debian", the glob that matches it must be something like index.docker.io/library/ubuntu. // If the image is a DockerHub used-owned image like "myuser/myapp", then the glob that matches it must be something like index.docker.io/myuser/myapp. // This means that the glob patterns "*" will not match the image name "ubuntu", and "*/*" will not match "myuser/myapp"; the "index.docker.io" prefix is required. // // If the image does not specify a tag (e.g., :latest or :v1.2.3), the tag ":latest" will be assumed. // // Note that the tag delimiter (":") does not act as a breaking separator for the purposes of a "*" glob. // To match any tag, the glob should end with ":**". func Match(glob, image string) (bool, error) { re, err := Compile(glob) if err != nil { return false, err } // TODO: do we want ":" to count as a separator like "/" is? ref, err := name.ParseReference(image, name.WeakValidation) if err != nil { return false, err } match := re.MatchString(ref.Name()) if !match && ref.Name() != image { // If the image was not fully qualified, try matching the glob against the original non-fully-qualified. // This should be a warning and this behavior should eventually be removed. match = re.MatchString(image) } return match, nil } ================================================ FILE: pkg/apis/glob/glob_test.go ================================================ // 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. package glob import ( "testing" ) func TestGlobMatch(t *testing.T) { for _, c := range []struct { image, glob string wantMatch bool wantErr bool }{ {image: "foo", glob: "index.docker.io/library/foo:latest", wantMatch: true}, {image: "foo", glob: "index.docker.io/library/foo:*", wantMatch: true}, {image: "foo", glob: "index.docker.io/library/*", wantMatch: true}, {image: "foo", glob: "index.docker.io/library/*:latest", wantMatch: true}, {image: "foo", glob: "index.docker.io/*/*", wantMatch: true}, {image: "foo", glob: "index.docker.io/**", wantMatch: true}, {image: "foo", glob: "index.docker.**", wantMatch: true}, {image: "foo", glob: "inde**", wantMatch: true}, {image: "foo", glob: "**", wantMatch: true}, {image: "foo", glob: "foo", wantMatch: true}, // matches because of deprecated fallback logic. {image: "foo", glob: "foo*", wantMatch: true}, // * matches 0+ characters {image: "foo", glob: "foo**", wantMatch: true}, // ** matches 0+ characters {image: "myuser/myapp", glob: "index.docker.io/myuser/myapp:latest", wantMatch: true}, {image: "myuser/myapp", glob: "index.docker.io/myuser/myapp:*", wantMatch: true}, {image: "myuser/myapp", glob: "index.docker.io/myuser/*", wantMatch: true}, {image: "myuser/myapp", glob: "index.docker.io/myuser/*:latest", wantMatch: true}, {image: "myuser/myapp", glob: "index.docker.io/*/*", wantMatch: true}, {image: "myuser/myapp", glob: "index.docker.io/**", wantMatch: true}, {image: "myuser/myapp", glob: "index.docker.**", wantMatch: true}, {image: "myuser/myapp", glob: "inde**", wantMatch: true}, {image: "myuser/myapp", glob: "**", wantMatch: true}, {image: "myuser/myapp", glob: "myuser/myapp", wantMatch: true}, // matches because of deprecated fallback logic. {image: "myuser/myapp", glob: "myuser/myapp*", wantMatch: true}, // * matches 0+ characters {image: "myuser/myapp", glob: "myuser/myapp**", wantMatch: true}, // ** matches 0+ characters // Fully qualified refs and globs. {image: "ghcr.io/foo/bar", glob: "ghcr.io/*/*", wantMatch: true}, {image: "ghcr.io/foo/bar", glob: "ghcr.io/**", wantMatch: true}, {image: "ghcr.io/foo", glob: "ghcr.io/*/*", wantMatch: false}, // doesn't match second * {image: "ghcr.io/foo", glob: "ghcr.io/**", wantMatch: true}, {image: "ghcr.io/foo", glob: "ghc**", wantMatch: true}, {image: "ghcr.io/foo", glob: "**", wantMatch: true}, {image: "ghcr.io/foo", glob: "*/**", wantMatch: true}, {image: "ghcr.io/foo", glob: "ghcr.io/foo*", wantMatch: true}, // * matches 0+ characters {image: "ghcr.io/foo", glob: "ghcr.io/foo**", wantMatch: true}, // ** matches 0+ characters // Various error cases. {image: "prefix-ghcr.io/foo", glob: "ghcr.io/foo", wantMatch: false}, // glob starts at beginning. {image: "ghcr.io/foo-suffix", glob: "ghcr.io/foo", wantMatch: false}, // glob ends at the end. {image: "ghcrxio/foo", glob: "ghcr.io/**", wantMatch: false}, // dots in glob are replaced with \., not treated as regexp . {image: "invalid&name", glob: "**", wantMatch: false, wantErr: true}, // invalid refs are not matched. {image: "invalid-glob", glob: ".+", wantMatch: false, wantErr: true}, // invalid globs are rejected. {image: "invalid-glob", glob: "[a-z]*", wantMatch: false, wantErr: true}, // invalid globs are rejected. // Upgrading unqualified globs to assume index.docker.io prefix. {image: "foo", glob: "*", wantMatch: true}, {image: "myuser/myapp", glob: "*/*", wantMatch: true}, // Image with digest (exact match) { image: "ghcr.io/foo@sha256:5504f2a95018e3d8a52d80d9e1a128c6ea337581808ff9fe96f5628ce2336350", glob: "ghcr.io/foo@sha256:5504f2a95018e3d8a52d80d9e1a128c6ea337581808ff9fe96f5628ce2336350", wantMatch: true, }, } { t.Run(c.image+"|"+c.glob, func(t *testing.T) { match, err := Match(c.glob, c.image) if match != c.wantMatch { t.Errorf("match: got %t, want %t", match, c.wantMatch) } if gotErr := err != nil; gotErr != c.wantErr { t.Errorf("err: got %v, want %t", err, c.wantErr) } }) } } ================================================ FILE: pkg/apis/policy/common/validation.go ================================================ // 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. package common import ( "errors" "fmt" "net" "regexp" "strings" "github.com/aws/aws-sdk-go-v2/aws/arn" registryfuncs "github.com/google/go-containerregistry/pkg/name" "github.com/sigstore/sigstore/pkg/signature/kms/aws" "github.com/sigstore/sigstore/pkg/signature/kms/azure" "github.com/sigstore/sigstore/pkg/signature/kms/gcp" "github.com/sigstore/sigstore/pkg/signature/kms/hashivault" "k8s.io/apimachinery/pkg/util/sets" "knative.dev/pkg/apis" ) const ( ociRepoDelimiter = "/" ) var ( SupportedKMSProviders = []string{aws.ReferenceScheme, azure.ReferenceScheme, hashivault.ReferenceScheme, gcp.ReferenceScheme} // TODO: create constants in to cosign? ValidPredicateTypes = sets.NewString("custom", "slsaprovenance", "spdx", "spdxjson", "cyclonedx", "link", "vuln") // If a static matches, define the behaviour for it. ValidStaticRefTypes = sets.NewString("fail", "pass") // Valid modes for a policy ValidModes = sets.NewString("enforce", "warn") // ValidResourceNames for a policy match selector. // By default, this is empty, which should allow any resource name, however, // this can be populated with the set of resources to allow in the validating // webhook, which should match the set of resources. ValidResourceNames = sets.NewString() ) func ValidateOCI(oci string) error { // We want to validate both registry uris only or registry with valid repository names parts := strings.SplitN(oci, ociRepoDelimiter, 2) if len(parts) == 2 && (strings.ContainsRune(parts[0], '.') || strings.ContainsRune(parts[0], ':')) { _, err := registryfuncs.NewRepository(oci, registryfuncs.StrictValidation) if err != nil { return err } return nil } _, err := registryfuncs.NewRegistry(oci, registryfuncs.StrictValidation) if err != nil { return err } return nil } var ( errKMSReference = errors.New("kms key should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)") // Key ID/ALIAS/ARN conforms to KMS standard documented here: https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id // Key format examples: // Key ID: awskms:///1234abcd-12ab-34cd-56ef-1234567890ab // Key ID with endpoint: awskms://localhost:4566/1234abcd-12ab-34cd-56ef-1234567890ab // Key ARN: awskms:///arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab // Key ARN with endpoint: awskms://localhost:4566/arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab // Alias name: awskms:///alias/ExampleAlias // Alias name with endpoint: awskms://localhost:4566/alias/ExampleAlias // Alias ARN: awskms:///arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias // Alias ARN with endpoint: awskms://localhost:4566/arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias uuidRE = `m?r?k?-?[A-Fa-f0-9]{8}-?[A-Fa-f0-9]{4}-?[A-Fa-f0-9]{4}-?[A-Fa-f0-9]{4}-?[A-Fa-f0-9]{12}` arnRE = `arn:(?:aws|aws-us-gov|aws-cn):kms:[a-z0-9-]+:\d{12}:` hostRE = `([^/]*)/` keyIDRE = regexp.MustCompile(`^awskms://` + hostRE + `(` + uuidRE + `)$`) keyARNRE = regexp.MustCompile(`^awskms://` + hostRE + `(` + arnRE + `key/` + uuidRE + `)$`) aliasNameRE = regexp.MustCompile(`^awskms://` + hostRE + `((alias/.*))$`) aliasARNRE = regexp.MustCompile(`^awskms://` + hostRE + `(` + arnRE + `(alias/.*))$`) allREs = []*regexp.Regexp{keyIDRE, keyARNRE, aliasNameRE, aliasARNRE} ) // validAWSKMSRegex returns a non-nil error if the reference string is invalid func validAWSKMSRegex(ref string) error { for _, re := range allREs { if re.MatchString(ref) { return nil } } return errKMSReference } // validateAWSKMS validates that the KMS conforms to AWS // KMS format: // awskms://$ENDPOINT/$KEYID // Where: // $ENDPOINT is optional // $KEYID is either the key ARN or an alias ARN // Key ID/ALIAS/ARN conforms to KMS standard documented here: https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id // Reasoning for only supporting these formats is that other // formats require additional configuration via ENV variables. func validateAWSKMS(kms string) *apis.FieldError { parts := strings.Split(kms, "/") // Either it is a key id reference or an endpoint, it should be composed of more than 4 parts. if len(parts) < 4 { return apis.ErrInvalidValue(kms, apis.CurrentField, "malformed AWS KMS format 'awskms://$ENDPOINT/$KEYID', should be conformant with KMS standard documented here: https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id") } // validate the awskms reference against valid regular expressions if err := validAWSKMSRegex(kms); err != nil { return apis.ErrInvalidValue(kms, apis.CurrentField, err.Error()) } endpoint := parts[2] // Sometimes this logic assumes the endpoint is part of the KEY e.g. awskms://arn:... // These examples are invalid, so we need to throw proper errors if endpoint != "" && (strings.HasPrefix(endpoint, "arn") || strings.HasPrefix(endpoint, "alias")) { return apis.ErrInvalidValue(kms, apis.CurrentField, errKMSReference.Error()) } // Even if the reference is valid, the endpoint could NOT be, only validate if not empty if endpoint != "" { _, _, err := net.SplitHostPort(endpoint) if err != nil { return apis.ErrInvalidValue(kms, apis.CurrentField, fmt.Sprintf("malformed endpoint: %s", err)) } } keyID := parts[3] arn, err := arn.Parse(keyID) if err != nil { return apis.ErrInvalidValue(kms, apis.CurrentField, fmt.Sprintf("failed to parse either key or alias arn: %s", err)) } // Only support key or alias ARN. if arn.Resource != "key" && arn.Resource != "alias" { return apis.ErrInvalidValue(kms, apis.CurrentField, fmt.Sprintf("Got ARN: %+v Resource: %s", arn, arn.Resource)) } return nil } func ValidateKMS(kms string) *apis.FieldError { var errs *apis.FieldError validPrefix := false for _, prefix := range SupportedKMSProviders { if strings.HasPrefix(kms, prefix) { validPrefix = true break } } if !validPrefix { return apis.ErrInvalidValue(kms, apis.CurrentField, fmt.Sprintf("malformed KMS format, should be prefixed by any of the supported providers: %v", SupportedKMSProviders)) } if strings.HasPrefix(kms, aws.ReferenceScheme) { errs = errs.Also(validateAWSKMS(kms)) } return errs } ================================================ FILE: pkg/apis/policy/common/validation_test.go ================================================ // 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. package common import ( "testing" "github.com/google/go-cmp/cmp" ) func TestValidateOCI(t *testing.T) { tests := []struct { oci string errorString string isError bool }{ { oci: "gcr.io", isError: false, }, { oci: "gcr.io/test/*", errorString: "repository can only contain the characters `abcdefghijklmnopqrstuvwxyz0123456789_-./`: test/*", isError: true, }, { oci: "gcr.@io/test", errorString: "registries must be valid RFC 3986 URI authorities: gcr.@io", isError: true, }, { oci: "ghcr.io/sigstore/test", isError: false, }, { oci: "registry.example.com", isError: false, }, { oci: "localhost:8080/test", isError: false, }, { oci: "localhost", isError: false, }, } for _, test := range tests { t.Run(test.oci, func(t *testing.T) { err := ValidateOCI(test.oci) if !test.isError && err != nil { t.Error("Unxpected error", err.Error()) } if test.isError { if diff := cmp.Diff(test.errorString, err.Error()); diff != "" { t.Error("Unexpected error mesage (-want, +got):", diff) } } }) } } ================================================ FILE: pkg/apis/policy/register.go ================================================ // 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. package policy import "k8s.io/apimachinery/pkg/runtime/schema" const ( // GroupName is the name of the API group. GroupName = "policy.sigstore.dev" DuckGroupName = "duck.policy.sigstore.dev" ) var ( // ClusterImagePolicyResource represents a ClusterImagePolicy ClusterImagePolicyResource = schema.GroupResource{ Group: GroupName, Resource: "clusterimagepolicies", } ) ================================================ FILE: pkg/apis/policy/v1alpha1/clusterimagepolicy_conversion.go ================================================ // 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. package v1alpha1 import ( "context" "fmt" "github.com/sigstore/policy-controller/pkg/apis/policy/v1beta1" v1 "k8s.io/api/core/v1" "knative.dev/pkg/apis" "knative.dev/pkg/ptr" ) var _ apis.Convertible = (*ClusterImagePolicy)(nil) // ConvertTo implements api.Convertible func (c *ClusterImagePolicy) ConvertTo(ctx context.Context, obj apis.Convertible) error { switch sink := obj.(type) { case *v1beta1.ClusterImagePolicy: sink.ObjectMeta = c.ObjectMeta sink.Status.Status = c.Status.DeepCopy().Status return c.Spec.ConvertTo(ctx, &sink.Spec) default: return fmt.Errorf("unknown version, got: %T", sink) } } // ConvertFrom implements api.Convertible func (c *ClusterImagePolicy) ConvertFrom(ctx context.Context, obj apis.Convertible) error { switch source := obj.(type) { case *v1beta1.ClusterImagePolicy: c.ObjectMeta = source.ObjectMeta c.Status.Status = source.Status.DeepCopy().Status return c.Spec.ConvertFrom(ctx, &source.Spec) default: return fmt.Errorf("unknown version, got: %T", c) } } func (spec *ClusterImagePolicySpec) ConvertTo(ctx context.Context, sink *v1beta1.ClusterImagePolicySpec) error { for _, image := range spec.Images { sink.Images = append(sink.Images, v1beta1.ImagePattern{Glob: image.Glob}) } for _, authority := range spec.Authorities { v1beta1Authority := v1beta1.Authority{} err := authority.ConvertTo(ctx, &v1beta1Authority) if err != nil { return err } sink.Authorities = append(sink.Authorities, v1beta1Authority) } for _, m := range spec.Match { v1beta1Match := v1beta1.MatchResource{} err := m.ConvertTo(ctx, &v1beta1Match) if err != nil { return err } sink.Match = append(sink.Match, v1beta1Match) } if spec.Policy != nil { sink.Policy = &v1beta1.Policy{} spec.Policy.ConvertTo(ctx, sink.Policy) } sink.Mode = spec.Mode return nil } func (matchResource *MatchResource) ConvertTo(_ context.Context, sink *v1beta1.MatchResource) error { sink.GroupVersionResource = *matchResource.GroupVersionResource.DeepCopy() if matchResource.ResourceSelector != nil { sink.ResourceSelector = matchResource.ResourceSelector.DeepCopy() } return nil } func (authority *Authority) ConvertTo(ctx context.Context, sink *v1beta1.Authority) error { sink.Name = authority.Name sink.SignatureFormat = authority.SignatureFormat if authority.CTLog != nil && authority.CTLog.URL != nil { sink.CTLog = &v1beta1.TLog{ URL: authority.CTLog.URL.DeepCopy(), TrustRootRef: authority.CTLog.TrustRootRef, } } if authority.RFC3161Timestamp != nil && authority.RFC3161Timestamp.TrustRootRef != "" { sink.RFC3161Timestamp = &v1beta1.RFC3161Timestamp{} sink.RFC3161Timestamp.TrustRootRef = authority.RFC3161Timestamp.TrustRootRef } for _, source := range authority.Sources { v1beta1Source := v1beta1.Source{} v1beta1Source.OCI = source.OCI v1beta1Source.TagPrefix = source.TagPrefix for _, sps := range source.SignaturePullSecrets { v1beta1Source.SignaturePullSecrets = append(v1beta1Source.SignaturePullSecrets, v1.LocalObjectReference{Name: sps.Name}) } sink.Sources = append(sink.Sources, v1beta1Source) } for _, att := range authority.Attestations { v1beta1Att := v1beta1.Attestation{} v1beta1Att.Name = att.Name v1beta1Att.PredicateType = att.PredicateType if att.Policy != nil { v1beta1Att.Policy = &v1beta1.Policy{} att.Policy.ConvertTo(ctx, v1beta1Att.Policy) } sink.Attestations = append(sink.Attestations, v1beta1Att) } if authority.Key != nil { sink.Key = &v1beta1.KeyRef{} authority.Key.ConvertTo(ctx, sink.Key) } if authority.Keyless != nil { sink.Keyless = &v1beta1.KeylessRef{ URL: authority.Keyless.URL.DeepCopy(), TrustRootRef: authority.Keyless.TrustRootRef, } for _, id := range authority.Keyless.Identities { sink.Keyless.Identities = append(sink.Keyless.Identities, v1beta1.Identity{Issuer: id.Issuer, Subject: id.Subject, IssuerRegExp: id.IssuerRegExp, SubjectRegExp: id.SubjectRegExp}) } if authority.Keyless.CACert != nil { sink.Keyless.CACert = &v1beta1.KeyRef{} authority.Keyless.CACert.ConvertTo(ctx, sink.Keyless.CACert) } if authority.Keyless.InsecureIgnoreSCT != nil { sink.Keyless.InsecureIgnoreSCT = authority.Keyless.InsecureIgnoreSCT } } if authority.Static != nil { sink.Static = &v1beta1.StaticRef{ Action: authority.Static.Action, Message: authority.Static.Message, } } return nil } func (p *Policy) ConvertTo(_ context.Context, sink *v1beta1.Policy) { sink.Type = p.Type sink.Data = p.Data if p.Remote != nil { sink.Remote = &v1beta1.RemotePolicy{ URL: p.Remote.URL, Sha256sum: p.Remote.Sha256sum, } } if p.ConfigMapRef != nil { sink.ConfigMapRef = &v1beta1.ConfigMapReference{ Name: p.ConfigMapRef.Name, Namespace: p.ConfigMapRef.Namespace, Key: p.ConfigMapRef.Key, } } if p.FetchConfigFile != nil { sink.FetchConfigFile = ptr.Bool(*p.FetchConfigFile) } if p.IncludeSpec != nil { sink.IncludeSpec = ptr.Bool(*p.IncludeSpec) } if p.IncludeObjectMeta != nil { sink.IncludeObjectMeta = ptr.Bool(*p.IncludeObjectMeta) } if p.IncludeTypeMeta != nil { sink.IncludeTypeMeta = ptr.Bool(*p.IncludeTypeMeta) } } func (p *Policy) ConvertFrom(_ context.Context, source *v1beta1.Policy) { p.Type = source.Type p.Data = source.Data if source.Remote != nil { p.Remote = &RemotePolicy{ URL: source.Remote.URL, Sha256sum: source.Remote.Sha256sum, } } if source.ConfigMapRef != nil { p.ConfigMapRef = &ConfigMapReference{ Name: source.ConfigMapRef.Name, Namespace: source.ConfigMapRef.Namespace, Key: source.ConfigMapRef.Key, } } if source.FetchConfigFile != nil { p.FetchConfigFile = ptr.Bool(*source.FetchConfigFile) } if source.IncludeSpec != nil { p.IncludeSpec = ptr.Bool(*source.IncludeSpec) } if source.IncludeObjectMeta != nil { p.IncludeObjectMeta = ptr.Bool(*source.IncludeObjectMeta) } if source.IncludeTypeMeta != nil { p.IncludeTypeMeta = ptr.Bool(*source.IncludeTypeMeta) } } func (key *KeyRef) ConvertTo(_ context.Context, sink *v1beta1.KeyRef) { sink.SecretRef = key.SecretRef.DeepCopy() sink.Data = key.Data sink.KMS = key.KMS sink.HashAlgorithm = key.HashAlgorithm } func (spec *ClusterImagePolicySpec) ConvertFrom(ctx context.Context, source *v1beta1.ClusterImagePolicySpec) error { for _, image := range source.Images { spec.Images = append(spec.Images, ImagePattern{Glob: image.Glob}) } for i := range source.Authorities { authority := Authority{} err := authority.ConvertFrom(ctx, &source.Authorities[i]) if err != nil { return err } spec.Authorities = append(spec.Authorities, authority) } for i := range source.Match { matchResource := MatchResource{} err := matchResource.ConvertFrom(ctx, &source.Match[i]) if err != nil { return err } spec.Match = append(spec.Match, matchResource) } spec.Mode = source.Mode if source.Policy != nil { spec.Policy = &Policy{} spec.Policy.ConvertFrom(ctx, source.Policy) } return nil } func (authority *Authority) ConvertFrom(ctx context.Context, source *v1beta1.Authority) error { authority.Name = source.Name authority.SignatureFormat = source.SignatureFormat if source.CTLog != nil && source.CTLog.URL != nil { authority.CTLog = &TLog{ URL: source.CTLog.URL.DeepCopy(), TrustRootRef: source.CTLog.TrustRootRef, } } if source.RFC3161Timestamp != nil && source.RFC3161Timestamp.TrustRootRef != "" { authority.RFC3161Timestamp = &RFC3161Timestamp{} authority.RFC3161Timestamp.TrustRootRef = source.RFC3161Timestamp.TrustRootRef } for _, s := range source.Sources { src := Source{} src.OCI = s.OCI src.TagPrefix = s.TagPrefix for _, sps := range s.SignaturePullSecrets { src.SignaturePullSecrets = append(src.SignaturePullSecrets, v1.LocalObjectReference{Name: sps.Name}) } authority.Sources = append(authority.Sources, src) } for _, att := range source.Attestations { attestation := Attestation{} attestation.Name = att.Name attestation.PredicateType = att.PredicateType if att.Policy != nil { attestation.Policy = &Policy{} attestation.Policy.ConvertFrom(ctx, att.Policy) } authority.Attestations = append(authority.Attestations, attestation) } if source.Key != nil { authority.Key = &KeyRef{} authority.Key.ConvertFrom(ctx, source.Key) } if source.Keyless != nil { authority.Keyless = &KeylessRef{ URL: source.Keyless.URL.DeepCopy(), TrustRootRef: source.Keyless.TrustRootRef, } for _, id := range source.Keyless.Identities { authority.Keyless.Identities = append(authority.Keyless.Identities, Identity{Issuer: id.Issuer, Subject: id.Subject, IssuerRegExp: id.IssuerRegExp, SubjectRegExp: id.SubjectRegExp}) } if source.Keyless.CACert != nil { authority.Keyless.CACert = &KeyRef{} authority.Keyless.CACert.ConvertFrom(ctx, source.Keyless.CACert) } if source.Keyless.InsecureIgnoreSCT != nil { authority.Keyless.InsecureIgnoreSCT = source.Keyless.InsecureIgnoreSCT } } if source.Static != nil { authority.Static = &StaticRef{ Action: source.Static.Action, Message: source.Static.Message, } } return nil } func (key *KeyRef) ConvertFrom(_ context.Context, source *v1beta1.KeyRef) { key.SecretRef = source.SecretRef.DeepCopy() key.Data = source.Data key.KMS = source.KMS key.HashAlgorithm = source.HashAlgorithm } func (matchResource *MatchResource) ConvertFrom(_ context.Context, source *v1beta1.MatchResource) error { matchResource.GroupVersionResource = *source.GroupVersionResource.DeepCopy() if source.ResourceSelector != nil { matchResource.ResourceSelector = source.ResourceSelector.DeepCopy() } return nil } ================================================ FILE: pkg/apis/policy/v1alpha1/clusterimagepolicy_conversion_test.go ================================================ // 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. package v1alpha1 import ( "context" "testing" "github.com/google/go-cmp/cmp" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/pkg/ptr" "github.com/sigstore/policy-controller/pkg/apis/policy/v1beta1" ) // Test v1alpha1 -> v1beta1 -> v1alpha1 func TestConversionRoundTripV1alpha1(t *testing.T) { tests := []struct { name string in *ClusterImagePolicy }{{name: "key and keyless", in: &ClusterImagePolicy{ ObjectMeta: metav1.ObjectMeta{ Name: "test-cip", }, Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "*"}}, Authorities: []Authority{ {Key: &KeyRef{ SecretRef: &v1.SecretReference{Name: "mysecret"}}}, {Keyless: &KeylessRef{ Identities: []Identity{{Subject: "subject", Issuer: "issuer"}}, CACert: &KeyRef{KMS: "kms", Data: "data", SecretRef: &v1.SecretReference{Name: "secret"}}, }}, }, }, }, }, {name: "key, keyless, and static, regexp", in: &ClusterImagePolicy{ ObjectMeta: metav1.ObjectMeta{ Name: "test-cip", }, Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "*"}}, Authorities: []Authority{ {Key: &KeyRef{ SecretRef: &v1.SecretReference{Name: "mysecret"}}}, {Keyless: &KeylessRef{ Identities: []Identity{{SubjectRegExp: "subjectregexp", IssuerRegExp: "issuerregexp"}}, CACert: &KeyRef{KMS: "kms", Data: "data", SecretRef: &v1.SecretReference{Name: "secret"}}, }}, {Static: &StaticRef{Action: "pass"}}, }, }, }, }, {name: "key and keyless, regexp", in: &ClusterImagePolicy{ ObjectMeta: metav1.ObjectMeta{ Name: "test-cip", }, Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "*"}}, Authorities: []Authority{ {Key: &KeyRef{ SecretRef: &v1.SecretReference{Name: "mysecret"}}}, {Keyless: &KeylessRef{ Identities: []Identity{{SubjectRegExp: "subjectregexp", IssuerRegExp: "issuerregexp"}}, CACert: &KeyRef{KMS: "kms", Data: "data", SecretRef: &v1.SecretReference{Name: "secret"}}, }}, }, }, }, }, {name: "source and attestations", in: &ClusterImagePolicy{ ObjectMeta: metav1.ObjectMeta{ Name: "test-cip", }, Spec: ClusterImagePolicySpec{ Mode: "warn", Images: []ImagePattern{{Glob: "*"}}, Authorities: []Authority{ {Key: &KeyRef{ SecretRef: &v1.SecretReference{Name: "mysecret"}}}, {Sources: []Source{{ OCI: "registry.example.com", TagPrefix: ptr.String("sbom"), SignaturePullSecrets: []v1.LocalObjectReference{{Name: "sps-secret"}}}}}, {Attestations: []Attestation{{ Name: "attestation-0", PredicateType: "vuln", Policy: &Policy{ Type: "cue", Data: "cue language goes here", }, }}}, }, }, }, }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { ver := &v1beta1.ClusterImagePolicy{} if err := test.in.ConvertTo(context.Background(), ver); err != nil { t.Error("ConvertTo() =", err) } got := &ClusterImagePolicy{} if err := got.ConvertFrom(context.Background(), ver); err != nil { t.Error("ConvertFrom() =", err) } if diff := cmp.Diff(test.in, got); diff != "" { t.Error("roundtrip (-want, +got) =", diff) } }) } } // Test v1beta1 -> v1alpha1 -> v1beta1 func TestConversionRoundTripV1beta1(t *testing.T) { tests := []struct { name string in *v1beta1.ClusterImagePolicy }{{name: "simple configuration", in: &v1beta1.ClusterImagePolicy{ ObjectMeta: metav1.ObjectMeta{ Name: "test-cip", }, Spec: v1beta1.ClusterImagePolicySpec{ Images: []v1beta1.ImagePattern{{Glob: "*"}}, }, }, }, {name: "another", in: &v1beta1.ClusterImagePolicy{ ObjectMeta: metav1.ObjectMeta{ Name: "test-cip", }, }, }, {name: "key, keyless, and static, regexp", in: &v1beta1.ClusterImagePolicy{ ObjectMeta: metav1.ObjectMeta{ Name: "test-cip", }, Spec: v1beta1.ClusterImagePolicySpec{ Images: []v1beta1.ImagePattern{{Glob: "*"}}, Authorities: []v1beta1.Authority{ {Key: &v1beta1.KeyRef{ SecretRef: &v1.SecretReference{Name: "mysecret"}}}, {Keyless: &v1beta1.KeylessRef{ Identities: []v1beta1.Identity{{SubjectRegExp: "subjectregexp", IssuerRegExp: "issuerregexp"}}, CACert: &v1beta1.KeyRef{KMS: "kms", Data: "data", SecretRef: &v1.SecretReference{Name: "secret"}}, }}, {Static: &v1beta1.StaticRef{Action: "pass"}}, }, }, }, }, {name: "key, keyless, and static, regexp, policy", in: &v1beta1.ClusterImagePolicy{ ObjectMeta: metav1.ObjectMeta{ Name: "test-cip", }, Spec: v1beta1.ClusterImagePolicySpec{ Images: []v1beta1.ImagePattern{{Glob: "*"}}, Authorities: []v1beta1.Authority{ {Key: &v1beta1.KeyRef{ SecretRef: &v1.SecretReference{Name: "mysecret"}}}, {Keyless: &v1beta1.KeylessRef{ Identities: []v1beta1.Identity{{SubjectRegExp: "subjectregexp", IssuerRegExp: "issuerregexp"}}, CACert: &v1beta1.KeyRef{KMS: "kms", Data: "data", SecretRef: &v1.SecretReference{Name: "secret"}}, }}, {Static: &v1beta1.StaticRef{Action: "pass"}}, }, Policy: &v1beta1.Policy{ Type: "cue", Data: "cue language goes here", }, }, }, }, {name: "key, keyless, and static, regexp, policy, fetchConfigFile, includeSpec", in: &v1beta1.ClusterImagePolicy{ ObjectMeta: metav1.ObjectMeta{ Name: "test-cip", }, Spec: v1beta1.ClusterImagePolicySpec{ Images: []v1beta1.ImagePattern{{Glob: "*"}}, Authorities: []v1beta1.Authority{ {Key: &v1beta1.KeyRef{ SecretRef: &v1.SecretReference{Name: "mysecret"}}}, {Keyless: &v1beta1.KeylessRef{ Identities: []v1beta1.Identity{{SubjectRegExp: "subjectregexp", IssuerRegExp: "issuerregexp"}}, CACert: &v1beta1.KeyRef{KMS: "kms", Data: "data", SecretRef: &v1.SecretReference{Name: "secret"}}, }}, {Static: &v1beta1.StaticRef{Action: "pass"}}, }, Policy: &v1beta1.Policy{ Type: "cue", Data: "cue language goes here", FetchConfigFile: ptr.Bool(true), IncludeSpec: ptr.Bool(true), }, }, }, }, {name: "key, keyless, and static, regexp, policy with cmref, fetchConfigFile, includeSpec", in: &v1beta1.ClusterImagePolicy{ ObjectMeta: metav1.ObjectMeta{ Name: "test-cip", }, Spec: v1beta1.ClusterImagePolicySpec{ Images: []v1beta1.ImagePattern{{Glob: "*"}}, Authorities: []v1beta1.Authority{ {Key: &v1beta1.KeyRef{ SecretRef: &v1.SecretReference{Name: "mysecret"}}, Attestations: []v1beta1.Attestation{{Policy: &v1beta1.Policy{ Type: "rego", ConfigMapRef: &v1beta1.ConfigMapReference{ Name: "cip-cmname", Key: "cip-keyname", }, }, }}}, {Keyless: &v1beta1.KeylessRef{ Identities: []v1beta1.Identity{{SubjectRegExp: "subjectregexp", IssuerRegExp: "issuerregexp"}}, CACert: &v1beta1.KeyRef{KMS: "kms", Data: "data", SecretRef: &v1.SecretReference{Name: "secret"}}, }}, {Static: &v1beta1.StaticRef{Action: "pass"}}, }, Policy: &v1beta1.Policy{ Type: "cue", ConfigMapRef: &v1beta1.ConfigMapReference{ Name: "cmname", Key: "keyname", }, FetchConfigFile: ptr.Bool(true), IncludeSpec: ptr.Bool(true), }, }, }, }, {name: "key, keyless, and static, regexp, policy, fetchConfigFile, includeSpec, includeObjectMeta, includeTypeMeta", in: &v1beta1.ClusterImagePolicy{ ObjectMeta: metav1.ObjectMeta{ Name: "test-cip", }, Spec: v1beta1.ClusterImagePolicySpec{ Images: []v1beta1.ImagePattern{{Glob: "*"}}, Authorities: []v1beta1.Authority{ {Key: &v1beta1.KeyRef{ SecretRef: &v1.SecretReference{Name: "mysecret"}}}, {Keyless: &v1beta1.KeylessRef{ Identities: []v1beta1.Identity{{SubjectRegExp: "subjectregexp", IssuerRegExp: "issuerregexp"}}, CACert: &v1beta1.KeyRef{KMS: "kms", Data: "data", SecretRef: &v1.SecretReference{Name: "secret"}}, }}, {Static: &v1beta1.StaticRef{Action: "pass"}}, }, Policy: &v1beta1.Policy{ Type: "cue", Data: "cue language goes here", FetchConfigFile: ptr.Bool(true), IncludeSpec: ptr.Bool(true), IncludeObjectMeta: ptr.Bool(true), IncludeTypeMeta: ptr.Bool(true), }, }, }, }, {name: "key, keyless, source, and rfc3161timestamp, regexp", in: &v1beta1.ClusterImagePolicy{ ObjectMeta: metav1.ObjectMeta{ Name: "test-cip", }, Spec: v1beta1.ClusterImagePolicySpec{ Images: []v1beta1.ImagePattern{{Glob: "*"}}, Authorities: []v1beta1.Authority{ {Key: &v1beta1.KeyRef{ SecretRef: &v1.SecretReference{Name: "mysecret"}}}, {Keyless: &v1beta1.KeylessRef{ Identities: []v1beta1.Identity{{SubjectRegExp: "subjectregexp", IssuerRegExp: "issuerregexp"}}, CACert: &v1beta1.KeyRef{KMS: "kms", Data: "data", SecretRef: &v1.SecretReference{Name: "secret"}}, }, RFC3161Timestamp: &v1beta1.RFC3161Timestamp{TrustRootRef: "trust-root-tsa-ref"}, }, {Sources: []v1beta1.Source{{ OCI: "registry.example.com", TagPrefix: ptr.String("sbom"), SignaturePullSecrets: []v1.LocalObjectReference{{Name: "sps-secret"}}}}}, }, }, }, }, {name: "key, keyless, and rfc3161timestamp, regexp", in: &v1beta1.ClusterImagePolicy{ ObjectMeta: metav1.ObjectMeta{ Name: "test-cip", }, Spec: v1beta1.ClusterImagePolicySpec{ Images: []v1beta1.ImagePattern{{Glob: "*"}}, Authorities: []v1beta1.Authority{ {Keyless: &v1beta1.KeylessRef{ Identities: []v1beta1.Identity{{SubjectRegExp: "subjectregexp", IssuerRegExp: "issuerregexp"}}, CACert: &v1beta1.KeyRef{KMS: "kms", Data: "data", SecretRef: &v1.SecretReference{Name: "secret"}}, InsecureIgnoreSCT: ptr.Bool(true), }, }, }, }, }, }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { ver := &ClusterImagePolicy{} if err := ver.ConvertFrom(context.Background(), test.in); err != nil { t.Error("ConvertDown() =", err) } got := &v1beta1.ClusterImagePolicy{} if err := ver.ConvertTo(context.Background(), got); err != nil { t.Error("ConvertUp() =", err) } if diff := cmp.Diff(test.in, got); diff != "" { t.Error("roundtrip (-want, +got) =", diff) } }) } } ================================================ FILE: pkg/apis/policy/v1alpha1/clusterimagepolicy_defaults.go ================================================ // 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. package v1alpha1 import ( "context" "fmt" "knative.dev/pkg/apis" ) // SetDefaults implements apis.Defaultable func (c *ClusterImagePolicy) SetDefaults(ctx context.Context) { c.Spec.SetDefaults(ctx) } func (spec *ClusterImagePolicySpec) SetDefaults(_ context.Context) { if spec.Mode == "" { spec.Mode = "enforce" } for i, authority := range spec.Authorities { if authority.Name == "" { spec.Authorities[i].Name = fmt.Sprintf("authority-%d", i) } if authority.Key == nil && authority.Static == nil && authority.Keyless != nil && authority.Keyless.CACert == nil && authority.Keyless.URL == nil { authority.Keyless.URL = apis.HTTPS("fulcio.sigstore.dev") } } } ================================================ FILE: pkg/apis/policy/v1alpha1/clusterimagepolicy_defaults_test.go ================================================ // 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. package v1alpha1 import ( "context" "testing" "knative.dev/pkg/apis" ) func TestNameDefaulting(t *testing.T) { tests := []struct { in *ClusterImagePolicy wantNames []string }{ {in: cipWithNames([]string{""}), wantNames: []string{"authority-0"}, }, {in: cipWithNames([]string{"", "vuln-scan"}), wantNames: []string{"authority-0", "vuln-scan"}, }, {in: cipWithNames([]string{"vuln-scan", ""}), wantNames: []string{"vuln-scan", "authority-1"}, }, {in: cipWithNames([]string{"first", "second"}), wantNames: []string{"first", "second"}, }} for _, tc := range tests { tc.in.SetDefaults(context.TODO()) if len(tc.in.Spec.Authorities) != len(tc.wantNames) { t.Fatalf("Mismatch number of wantNames: %d vs authorities: %d", len(tc.wantNames), len(tc.in.Spec.Authorities)) } for i, wantName := range tc.wantNames { if tc.in.Spec.Authorities[i].Name != wantName { t.Errorf("Wanted name: %s got %s", wantName, tc.in.Spec.Authorities[i].Name) } } } } func TestModeDefaulting(t *testing.T) { tests := []struct { name string mode string wantMode string }{{ name: "empty", wantMode: "enforce", }, { name: "enforce", mode: "enforce", wantMode: "enforce", }, { name: "warn", mode: "warn", wantMode: "warn", }} for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { tc := tc in := ClusterImagePolicy{Spec: ClusterImagePolicySpec{Mode: tc.mode}} in.SetDefaults(context.TODO()) if in.Spec.Mode != tc.wantMode { t.Errorf("Wanted mode: %s got %s", tc.wantMode, in.Spec.Mode) } }) } } func TestKeylessURLDefaulting(t *testing.T) { tests := []struct { name string in *ClusterImagePolicy wantURL string }{ {name: "static specified, no default", in: &ClusterImagePolicy{Spec: ClusterImagePolicySpec{Authorities: []Authority{{Static: &StaticRef{Action: "pass"}}}}}}, {name: "key specified, no default", in: &ClusterImagePolicy{Spec: ClusterImagePolicySpec{Authorities: []Authority{{Key: &KeyRef{Data: "Keydata here"}}}}}}, {name: "kms specified, no default", in: &ClusterImagePolicy{Spec: ClusterImagePolicySpec{Authorities: []Authority{{Keyless: &KeylessRef{CACert: &KeyRef{KMS: "Keydata here"}}}}}}}, {name: "keyless specified, do not overwite fulcio", in: &ClusterImagePolicy{Spec: ClusterImagePolicySpec{Authorities: []Authority{{Keyless: &KeylessRef{URL: apis.HTTP("fulcio.fulcio-system.svc")}}}}}, wantURL: "http://fulcio.fulcio-system.svc", }, {name: "keyless specified, public fulcio", in: &ClusterImagePolicy{Spec: ClusterImagePolicySpec{Authorities: []Authority{{Keyless: &KeylessRef{Identities: []Identity{{Issuer: "someissuer"}}}}}}}, wantURL: "https://fulcio.sigstore.dev", }, } for _, tc := range tests { in := tc.in.DeepCopy() in.SetDefaults(context.TODO()) switch tc.wantURL { case "": if in.Spec.Authorities[0].Keyless != nil && in.Spec.Authorities[0].Keyless.URL != nil { t.Errorf("Wanted no defaulting, got %s", in.Spec.Authorities[0].Keyless.URL) } default: if in.Spec.Authorities[0].Keyless == nil || in.Spec.Authorities[0].Keyless.URL == nil { t.Errorf("Wanted defaulting %s, got none", tc.wantURL) } else if in.Spec.Authorities[0].Keyless.URL.String() != tc.wantURL { t.Errorf("Wanted defaulting %s, got %s", tc.wantURL, in.Spec.Authorities[0].Keyless.URL) } } } } func cipWithNames(names []string) *ClusterImagePolicy { cip := &ClusterImagePolicy{ Spec: ClusterImagePolicySpec{}, } for _, name := range names { cip.Spec.Authorities = append(cip.Spec.Authorities, Authority{Name: name, Keyless: &KeylessRef{URL: &apis.URL{Host: "tests.example.com"}}}) } return cip } ================================================ FILE: pkg/apis/policy/v1alpha1/clusterimagepolicy_lifecycle.go ================================================ // Copyright 2023 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. package v1alpha1 import ( "knative.dev/pkg/apis" ) const ( inlineKeysFailedReason = "InliningKeysFailed" inlinePoliciesFailedReason = "InliningPoliciesFailed" updateCMFailedReason = "UpdatingConfigMap" ) var cipCondSet = apis.NewLivingConditionSet( ClusterImagePolicyConditionKeysInlined, ClusterImagePolicyConditionPoliciesInlined, ClusterImagePolicyConditionCMUpdated, ) // GetConditionSet retrieves the condition set for this resource. // Implements the KRShaped interface. func (*ClusterImagePolicy) GetConditionSet() apis.ConditionSet { return cipCondSet } // IsReady returns if the ClusterImagePolicy was compiled successfully to // ConfigMap. func (c *ClusterImagePolicy) IsReady() bool { cs := c.Status return cs.ObservedGeneration == c.Generation && cs.GetCondition(ClusterImagePolicyConditionReady).IsTrue() } // IsFailed returns true if the resource has observed // the latest generation and ready is false. func (c *ClusterImagePolicy) IsFailed() bool { cs := c.Status return cs.ObservedGeneration == c.Generation && cs.GetCondition(ClusterImagePolicyConditionReady).IsFalse() } // InitializeConditions sets the initial values to the conditions. func (cs *ClusterImagePolicyStatus) InitializeConditions() { cipCondSet.Manage(cs).InitializeConditions() } // MarkInlineKeysFailed surfaces a failure that we were unable to inline // the keys (from secrets or from KMS). func (cs *ClusterImagePolicyStatus) MarkInlineKeysFailed(msg string) { cipCondSet.Manage(cs).MarkFalse(ClusterImagePolicyConditionKeysInlined, inlineKeysFailedReason, msg) } // MarkInlineKeysOk marks the status saying that the inlining of the keys // had no errors. func (cs *ClusterImagePolicyStatus) MarkInlineKeysOk() { cipCondSet.Manage(cs).MarkTrue(ClusterImagePolicyConditionKeysInlined) } // MarkInlinePoliciesFailed surfaces a failure that we were unable to inline // the policies, either from ConfigMap or from URL. func (cs *ClusterImagePolicyStatus) MarkInlinePoliciesFailed(msg string) { cipCondSet.Manage(cs).MarkFalse(ClusterImagePolicyConditionPoliciesInlined, inlinePoliciesFailedReason, msg) } // MarkInlinePoliciesdOk marks the status saying that the inlining of the // policies had no errors. func (cs *ClusterImagePolicyStatus) MarkInlinePoliciesOk() { cipCondSet.Manage(cs).MarkTrue(ClusterImagePolicyConditionPoliciesInlined) } // MarkCMUpdateFailed surfaces a failure that we were unable to reflect the // CIP into the compiled ConfigMap. func (cs *ClusterImagePolicyStatus) MarkCMUpdateFailed(msg string) { cipCondSet.Manage(cs).MarkFalse(ClusterImagePolicyConditionCMUpdated, updateCMFailedReason, msg) } // MarkCMUpdated marks the status saying that the ConfigMap has been updated. func (cs *ClusterImagePolicyStatus) MarkCMUpdatedOK() { cipCondSet.Manage(cs).MarkTrue(ClusterImagePolicyConditionCMUpdated) } ================================================ FILE: pkg/apis/policy/v1alpha1/clusterimagepolicy_lifecycle_test.go ================================================ // 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. package v1alpha1 import ( "testing" corev1 "k8s.io/api/core/v1" "knative.dev/pkg/apis" "knative.dev/pkg/apis/duck" duckv1 "knative.dev/pkg/apis/duck/v1" ) func TestClusterImagePolicyDuckTypes(t *testing.T) { tests := []struct { name string t duck.Implementable }{{ name: "conditions", t: &duckv1.Conditions{}, }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { err := duck.VerifyType(&ClusterImagePolicy{}, test.t) if err != nil { t.Errorf("VerifyType(ClusterImagePolicy, %T) = %v", test.t, err) } }) } } func TestClusterImagePolicyGetConditionSet(t *testing.T) { r := &ClusterImagePolicy{} if got, want := r.GetConditionSet().GetTopLevelConditionType(), apis.ConditionReady; got != want { t.Errorf("GetTopLevelCondition=%v, want=%v", got, want) } } func TestClusterImagePolicyIsReady(t *testing.T) { cases := []struct { name string status ClusterImagePolicyStatus isReady bool }{{ name: "empty status should not be ready", status: ClusterImagePolicyStatus{}, isReady: false, }, { name: "Single condition type ready should not be ready", status: ClusterImagePolicyStatus{ Status: duckv1.Status{ Conditions: duckv1.Conditions{{ Type: ClusterImagePolicyConditionCMUpdated, Status: corev1.ConditionTrue, }}, }, }, isReady: false, }, { name: "False condition status should not be ready", status: ClusterImagePolicyStatus{ Status: duckv1.Status{ Conditions: duckv1.Conditions{{ Type: ClusterImagePolicyConditionCMUpdated, Status: corev1.ConditionFalse, }}, }, }, isReady: false, }, { name: "Unknown condition status should not be ready", status: ClusterImagePolicyStatus{ Status: duckv1.Status{ Conditions: duckv1.Conditions{{ Type: ClusterImagePolicyConditionReady, Status: corev1.ConditionUnknown, }}, }, }, isReady: false, }, { name: "Missing condition status should not be ready", status: ClusterImagePolicyStatus{ Status: duckv1.Status{ Conditions: duckv1.Conditions{{ Type: ClusterImagePolicyConditionReady, }}, }, }, isReady: false, }, { name: "True condition status should be ready", status: ClusterImagePolicyStatus{ Status: duckv1.Status{ Conditions: duckv1.Conditions{{ Type: ClusterImagePolicyConditionReady, Status: corev1.ConditionTrue, }}, }, }, isReady: true, }, { name: "All conditions with ready status should be ready", status: ClusterImagePolicyStatus{ Status: duckv1.Status{ Conditions: duckv1.Conditions{{ Type: ClusterImagePolicyConditionPoliciesInlined, Status: corev1.ConditionTrue, }, { Type: ClusterImagePolicyConditionKeysInlined, Status: corev1.ConditionTrue, }, { Type: ClusterImagePolicyConditionCMUpdated, Status: corev1.ConditionTrue, }, { Type: ClusterImagePolicyConditionReady, Status: corev1.ConditionTrue, }}, }, }, isReady: true, }, { name: "Multiple conditions with ready status false should not be ready", status: ClusterImagePolicyStatus{ Status: duckv1.Status{ Conditions: duckv1.Conditions{{ Type: ClusterImagePolicyConditionKeysInlined, Status: corev1.ConditionTrue, }, { Type: ClusterImagePolicyConditionReady, Status: corev1.ConditionFalse, }}, }, }, isReady: false, }} for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { r := ClusterImagePolicy{Status: tc.status} if e, a := tc.isReady, r.IsReady(); e != a { t.Errorf("%q expected: %v got: %v", tc.name, e, a) } r.Generation = 1 r.Status.ObservedGeneration = 2 if r.IsReady() { t.Error("Expected IsReady() to be false when Generation != ObservedGeneration") } }) } } func TestClusterImagePolicyIsFailed(t *testing.T) { cases := []struct { name string status ClusterImagePolicyStatus isFailed bool }{{ name: "empty status should not be failed", status: ClusterImagePolicyStatus{}, isFailed: false, }, { name: "False condition status should be failed", status: ClusterImagePolicyStatus{ Status: duckv1.Status{ Conditions: duckv1.Conditions{{ Type: ClusterImagePolicyConditionReady, Status: corev1.ConditionFalse, }}, }, }, isFailed: true, }, { name: "Unknown condition status should not be failed", status: ClusterImagePolicyStatus{ Status: duckv1.Status{ Conditions: duckv1.Conditions{{ Type: ClusterImagePolicyConditionReady, Status: corev1.ConditionUnknown, }}, }, }, isFailed: false, }, { name: "Missing condition status should not be failed", status: ClusterImagePolicyStatus{ Status: duckv1.Status{ Conditions: duckv1.Conditions{{ Type: ClusterImagePolicyConditionReady, }}, }, }, isFailed: false, }, { name: "True condition status should not be failed", status: ClusterImagePolicyStatus{ Status: duckv1.Status{ Conditions: duckv1.Conditions{{ Type: ClusterImagePolicyConditionReady, Status: corev1.ConditionTrue, }}, }, }, isFailed: false, }} for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { r := ClusterImagePolicy{Status: tc.status} if e, a := tc.isFailed, r.IsFailed(); e != a { t.Errorf("%q expected: %v got: %v", tc.name, e, a) } }) } } ================================================ FILE: pkg/apis/policy/v1alpha1/clusterimagepolicy_types.go ================================================ // 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. package v1alpha1 import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" "knative.dev/pkg/kmeta" ) // ClusterImagePolicy defines the images that go through verification // and the authorities used for verification // // +genclient // +genclient:nonNamespaced // +genreconciler:krshapedlogic=true // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type ClusterImagePolicy struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata"` // Spec holds the desired state of the ClusterImagePolicy (from the client). Spec ClusterImagePolicySpec `json:"spec"` // Status represents the current state of the ClusterImagePolicy. // This data may be out of date. // +optional Status ClusterImagePolicyStatus `json:"status,omitempty"` } var ( _ apis.Validatable = (*ClusterImagePolicy)(nil) _ apis.Defaultable = (*ClusterImagePolicy)(nil) _ kmeta.OwnerRefable = (*ClusterImagePolicy)(nil) // Check that the type conforms to the duck Knative Resource shape. _ duckv1.KRShaped = (*ClusterImagePolicy)(nil) ) const ( // ClusterImagePolicyConditionReady is set when the ClusterImagePolicy has // been compiled into the underlying ConfigMap properly. ClusterImagePolicyConditionReady = apis.ConditionReady // ClusterImagePolicyConditionKeysInlined is set to True when all the Keys // have been (Secrets, KMS, etc.) resolved, fetched, validated, and inlined // into the compiled representation. // In failure cases, the Condition will describe the errors in detail. ClusterImagePolicyConditionKeysInlined apis.ConditionType = "KeysInlined" // ClusterImagePolicyConditionPoliciesInlined is set to True when all the // policies have been resolved, fetched, validated, and inlined into the // compiled representation. // In failure cases, the Condition will describe the errors in detail. ClusterImagePolicyConditionPoliciesInlined apis.ConditionType = "PoliciesInlined" // ClusterImagePolicyConditionCMUpdated is set to True when the CIP has been // successfully added into the ConfigMap holding all the compiled CIPs. // In failure cases, the Condition will describe the errors in detail. ClusterImagePolicyConditionCMUpdated apis.ConditionType = "ConfigMapUpdated" ) // GetGroupVersionKind implements kmeta.OwnerRefable func (c *ClusterImagePolicy) GetGroupVersionKind() schema.GroupVersionKind { return SchemeGroupVersion.WithKind("ClusterImagePolicy") } // ClusterImagePolicySpec defines a list of images that should be verified type ClusterImagePolicySpec struct { // Images defines the patterns of image names that should be subject to this policy. Images []ImagePattern `json:"images"` // Authorities defines the rules for discovering and validating signatures. // +optional Authorities []Authority `json:"authorities,omitempty"` // Policy is an optional policy that can be applied against all the // successfully validated Authorities. If no authorities pass, this does // not even get evaluated, as the Policy is considered failed. // +optional Policy *Policy `json:"policy,omitempty"` // Mode controls whether a failing policy will be rejected (not admitted), // or if errors are converted to Warnings. // enforce - Reject (default) // warn - allow but warn // +optional Mode string `json:"mode,omitempty"` // Match allows selecting resources based on their properties. // +optional Match []MatchResource `json:"match,omitempty"` } // ImagePattern defines a pattern and its associated authorties // If multiple patterns match a particular image, then ALL of // those authorities must be satisfied for the image to be admitted. type ImagePattern struct { // Glob defines a globbing pattern. Glob string `json:"glob"` } // The authorities block defines the rules for discovering and // validating signatures. Signatures are // cryptographically verified using one of the "key" or "keyless" // fields. // When multiple authorities are specified, any of them may be used // to source the valid signature we are looking for to admit an // image. type Authority struct { // Name is the name for this authority. Used by the CIP Policy // validator to be able to reference matching signature or attestation // verifications. // If not specified, the name will be authority- Name string `json:"name"` // Key defines the type of key to validate the image. // +optional Key *KeyRef `json:"key,omitempty"` // Keyless sets the configuration to verify the authority against a Fulcio instance. // +optional Keyless *KeylessRef `json:"keyless,omitempty"` // Static specifies that signatures / attestations are not validated but // instead a static policy is applied against matching images. // +optional Static *StaticRef `json:"static,omitempty"` // Sources sets the configuration to specify the sources from where to consume the signature and attestations. // +optional Sources []Source `json:"source,omitempty"` // CTLog sets the configuration to verify the authority against a Rekor instance. // +optional CTLog *TLog `json:"ctlog,omitempty"` // Attestations is a list of individual attestations for this authority, // once the signature for this authority has been verified. // +optional Attestations []Attestation `json:"attestations,omitempty"` // RFC3161Timestamp sets the configuration to verify the signature timestamp against a RFC3161 time-stamping instance. // +optional RFC3161Timestamp *RFC3161Timestamp `json:"rfc3161timestamp,omitempty"` // SignatureFormat specifies the format the authority expects. Supported // formats are "legacy" and "bundle". If not specified, the default // is "legacy" (cosign's default). SignatureFormat string `json:"signatureFormat,omitempty"` } // This references a public verification key stored in // a secret in the cosign-system namespace. // A KeyRef must specify only one of SecretRef, Data or KMS type KeyRef struct { // SecretRef sets a reference to a secret with the key. // +optional SecretRef *v1.SecretReference `json:"secretRef,omitempty"` // Data contains the inline public key // +optional Data string `json:"data,omitempty"` // KMS contains the KMS url of the public key // Supported formats differ based on the KMS system used. // +optional KMS string `json:"kms,omitempty"` // HashAlgorithm always defaults to sha256 if the algorithm hasn't been explicitly set // +optional HashAlgorithm string `json:"hashAlgorithm,omitempty"` } // StaticRef specifies that signatures / attestations are not validated but // instead a static policy is applied against matching images. type StaticRef struct { // Action defines how to handle a matching policy. Action string `json:"action"` // For fail actions, emit an optional custom message. This only makes // sense for 'fail' action because on 'pass' there's no place to jot down // the message. Message string `json:"message,omitempty"` } // Source specifies the location of the signature / attestations. type Source struct { // OCI defines the registry from where to pull the signature / attestations. // +optional OCI string `json:"oci,omitempty"` // SignaturePullSecrets is an optional list of references to secrets in the // same namespace as the deploying resource for pulling any of the signatures // used by this Source. // +optional SignaturePullSecrets []v1.LocalObjectReference `json:"signaturePullSecrets,omitempty"` // TagPrefix is an optional prefix that signature and attestations have. // This is the 'tag based discovery' and in the future once references are // fully supported that should likely be the preferred way to handle these. // +optional TagPrefix *string `json:"tagPrefix,omitempty"` } // TLog specifies the URL to a transparency log that holds // the signature and public key information type TLog struct { // URL sets the url to the rekor instance (by default the public rekor.sigstore.dev) // +optional URL *apis.URL `json:"url,omitempty"` // Use the Public Key from the referred TrustRoot.TLog // +optional TrustRootRef string `json:"trustRootRef,omitempty"` } // KeylessRef contains location of the validating certificate and the identities // against which to verify. KeylessRef will contain either the URL to the verifying // certificate, or it will contain the certificate data inline or in a secret. type KeylessRef struct { // URL defines a url to the keyless instance. // +optional URL *apis.URL `json:"url,omitempty"` // Identities sets a list of identities. Identities []Identity `json:"identities"` // CACert sets a reference to CA certificate // +optional CACert *KeyRef `json:"ca-cert,omitempty"` // Use the Certificate Chain from the referred TrustRoot.CertificateAuthorities and TrustRoot.CTLog // +optional TrustRootRef string `json:"trustRootRef,omitempty"` // InsecureIgnoreSCT omits verifying if a certificate contains an embedded SCT // +optional InsecureIgnoreSCT *bool `json:"insecureIgnoreSCT,omitempty"` } // Attestation defines the type of attestation to validate and optionally // apply a policy decision to it. Authority block is used to verify the // specified attestation types, and if Policy is specified, then it's applied // only after the validation of the Attestation signature has been verified. type Attestation struct { // Name of the attestation. These can then be referenced at the CIP level // policy. Name string `json:"name"` // PredicateType defines which predicate type to verify. Matches cosign verify-attestation options. PredicateType string `json:"predicateType"` // Policy defines all of the matching signatures, and all of // the matching attestations (whose attestations are verified). // +optional Policy *Policy `json:"policy,omitempty"` } // MatchResource allows selecting resources based on its version, group and resource. // It is also possible to select resources based on a list of matching labels. type MatchResource struct { // +optional metav1.GroupVersionResource `json:",inline"` // +optional ResourceSelector *metav1.LabelSelector `json:"selector,omitempty"` } // RemotePolicy defines all the properties to fetch a remote policy type RemotePolicy struct { // URL to the policy data. URL apis.URL `json:"url,omitempty"` // Sha256sum defines the exact sha256sum computed out of the 'body' of the http response. Sha256sum string `json:"sha256sum,omitempty"` } // Policy specifies a policy to use for Attestation or the CIP validation (iff // at least one authority matches). // Exactly one of Data, URL, or ConfigMapReference must be specified. type Policy struct { // Which kind of policy this is, currently only rego or cue are supported. // Furthermore, only cue is tested :) Type string `json:"type"` // Data contains the policy definition. // +optional Data string `json:"data,omitempty"` // Remote defines the url to a policy. // +optional Remote *RemotePolicy `json:"remote,omitempty"` // ConfigMapRef defines the reference to a configMap with the policy definition. // +optional ConfigMapRef *ConfigMapReference `json:"configMapRef,omitempty"` // FetchConfigFile controls whether ConfigFile will be fetched and made // available for CIP level policy evaluation. Note that this only gets // evaluated (and hence fetched) iff at least one authority matches. // The ConfigFile will then be available in this format: // https://github.com/opencontainers/image-spec/blob/main/config.md // +optional FetchConfigFile *bool `json:"fetchConfigFile,omitempty"` // IncludeSpec controls whether resource `Spec` will be included and // made available for CIP level policy evaluation. Note that this only gets // evaluated iff at least one authority matches. // Also note that because Spec may be of a different shape depending // on the resource being evaluatied (see MatchResource for filtering) // you might want to configure these to match the policy file to ensure // the shape of the Spec is what you expect when evaling the policy. // +optional IncludeSpec *bool `json:"includeSpec,omitempty"` // IncludeObjectMeta controls whether the ObjectMeta will be included and // made available for CIP level policy evalutation. Note that this only gets // evaluated iff at least one authority matches. // +optional IncludeObjectMeta *bool `json:"includeObjectMeta,omitempty"` // IncludeTypeMeta controls whether the TypeMeta will be included and // made available for CIP level policy evalutation. Note that this only gets // evaluated iff at least one authority matches. // +optional IncludeTypeMeta *bool `json:"includeTypeMeta,omitempty"` } // ConfigMapReference is cut&paste from SecretReference, but for the life of me // couldn't find one in the public types. If there's one, use it. type ConfigMapReference struct { // Name is unique within a namespace to reference a configmap resource. // +optional Name string `json:"name,omitempty"` // Namespace defines the space within which the configmap name must be unique. // +optional Namespace string `json:"namespace,omitempty"` // Key defines the key to pull from the configmap. // +optional Key string `json:"key,omitempty"` } // Identity may contain the issuer and/or the subject found in the transparency // log. // Issuer/Subject uses a strict match, while IssuerRegExp and SubjectRegExp // apply a regexp for matching. type Identity struct { // Issuer defines the issuer for this identity. // +optional Issuer string `json:"issuer,omitempty"` // Subject defines the subject for this identity. // +optional Subject string `json:"subject,omitempty"` // IssuerRegExp specifies a regular expression to match the issuer for this identity. // +optional IssuerRegExp string `json:"issuerRegExp,omitempty"` // SubjectRegExp specifies a regular expression to match the subject for this identity. // +optional SubjectRegExp string `json:"subjectRegExp,omitempty"` } // RFC3161Timestamp specifies the URL to a RFC3161 time-stamping server that holds // the time-stamped verification for the signature type RFC3161Timestamp struct { // Use the Certificate Chain from the referred TrustRoot.TimeStampAuthorities // +optional TrustRootRef string `json:"trustRootRef,omitempty"` } // ClusterImagePolicyStatus represents the current state of a // ClusterImagePolicy. type ClusterImagePolicyStatus struct { // inherits duck/v1 Status, which currently provides: // * ObservedGeneration - the 'Generation' of the Broker that was last processed by the controller. // * Conditions - the latest available observations of a resource's current state. duckv1.Status `json:",inline"` } // GetStatus retrieves the status of the ClusterImagePolicy. // Implements the KRShaped interface. func (c *ClusterImagePolicy) GetStatus() *duckv1.Status { return &c.Status.Status } // ClusterImagePolicyList is a list of ClusterImagePolicy resources // // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type ClusterImagePolicyList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata"` Items []ClusterImagePolicy `json:"items"` } ================================================ FILE: pkg/apis/policy/v1alpha1/clusterimagepolicy_validation.go ================================================ // 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. package v1alpha1 import ( "context" "fmt" "net/url" "path/filepath" "regexp" "github.com/sigstore/policy-controller/pkg/apis/glob" "github.com/sigstore/policy-controller/pkg/apis/policy/common" "github.com/sigstore/policy-controller/pkg/apis/signaturealgo" "github.com/sigstore/sigstore/pkg/cryptoutils" "knative.dev/pkg/apis" "knative.dev/pkg/system" policycontrollerconfig "github.com/sigstore/policy-controller/pkg/config" ) // Validate implements apis.Validatable func (c *ClusterImagePolicy) Validate(ctx context.Context) *apis.FieldError { // If we're doing status updates, do not validate the spec. if apis.IsInStatusUpdate(ctx) { return nil } return c.Spec.Validate(ctx).ViaField("spec") } func (spec *ClusterImagePolicySpec) Validate(ctx context.Context) (errors *apis.FieldError) { // Check what the configuration is and act accordingly. pcConfig := policycontrollerconfig.FromContextOrDefaults(ctx) if len(spec.Images) == 0 { errors = errors.Also(apis.ErrMissingField("images")) } for i, image := range spec.Images { errors = errors.Also(image.Validate(ctx).ViaFieldIndex("images", i)) } if len(spec.Authorities) == 0 && pcConfig.FailOnEmptyAuthorities { errors = errors.Also(apis.ErrMissingField("authorities")) } for i, authority := range spec.Authorities { errors = errors.Also(authority.Validate(ctx).ViaFieldIndex("authorities", i)) } if spec.Mode != "" && !common.ValidModes.Has(spec.Mode) { errors = errors.Also(apis.ErrInvalidValue(spec.Mode, "mode", "unsupported mode")) } for i, m := range spec.Match { errors = errors.Also(m.Validate(ctx).ViaFieldIndex("match", i)) } // Note that we're within Spec here so that we can validate that the policy // FetchConfigFile is only set within Spec.Policy. errors = errors.Also(spec.Policy.Validate(apis.WithinSpec(ctx))) return } func (image *ImagePattern) Validate(_ context.Context) *apis.FieldError { if image.Glob == "" { return apis.ErrMissingField("glob") } return ValidateGlob(image.Glob).ViaField("glob") } func (authority *Authority) Validate(ctx context.Context) *apis.FieldError { var errs *apis.FieldError if authority.Key == nil && authority.Keyless == nil && authority.Static == nil { errs = errs.Also(apis.ErrMissingOneOf("key", "keyless", "static")) // Instead of returning all the missing subfields, just return here // to give a more concise and arguably a more meaningful error message. return errs } if (authority.Key != nil && authority.Keyless != nil) || (authority.Key != nil && authority.Static != nil) || (authority.Keyless != nil && authority.Static != nil) { errs = errs.Also(apis.ErrMultipleOneOf("key", "keyless", "static")) // Instead of returning all the missing subfields, just return here // to give a more concise and arguably a more meaningful error message. return errs } if authority.Key != nil { errs = errs.Also(authority.Key.Validate(ctx).ViaField("key")) } if authority.Keyless != nil { errs = errs.Also(authority.Keyless.Validate(ctx).ViaField("keyless")) } if authority.Static != nil { errs = errs.Also(authority.Static.Validate(ctx).ViaField("static")) // Attestations, Sources, or CTLog do not make sense with static policy. if len(authority.Attestations) > 0 { errs = errs.Also(apis.ErrMultipleOneOf("static", "attestations")) } if len(authority.Sources) > 0 { errs = errs.Also(apis.ErrMultipleOneOf("static", "source")) } if authority.CTLog != nil { errs = errs.Also(apis.ErrMultipleOneOf("static", "ctlog")) } if authority.RFC3161Timestamp != nil { errs = errs.Also(apis.ErrMultipleOneOf("static", "rfc3161timestamp")) } } if len(authority.Sources) > 1 { errs = errs.Also(apis.ErrInvalidValue("source", "source", "only single source is supported")) } else { // If there are multiple sources, don't complain about each of them. for i, source := range authority.Sources { errs = errs.Also(source.Validate(ctx).ViaFieldIndex("source", i)) } } for _, att := range authority.Attestations { errs = errs.Also(att.Validate(ctx).ViaField("attestations")) } return errs } func (s *StaticRef) Validate(_ context.Context) *apis.FieldError { var errs *apis.FieldError if s.Action == "" { errs = errs.Also(apis.ErrMissingField("action")) } else if !common.ValidStaticRefTypes.Has(s.Action) { errs = errs.Also(apis.ErrInvalidValue(s.Action, "action", "unsupported action")) } return errs } func (matchResource *MatchResource) Validate(_ context.Context) *apis.FieldError { var errs *apis.FieldError if matchResource.Resource != "" && common.ValidResourceNames.Len() > 0 && !common.ValidResourceNames.Has(matchResource.Resource) { errs = errs.Also(apis.ErrInvalidValue(matchResource.Resource, "resource", "unsupported resource name")) } if matchResource.ResourceSelector != nil && (matchResource.Resource == "" && matchResource.Version == "" && matchResource.Group == "") { errs = errs.Also(apis.ErrInvalidValue(matchResource.Resource, "selector", "selector requires a resource type to match the labels")) } return errs } func (key *KeyRef) Validate(_ context.Context) *apis.FieldError { var errs *apis.FieldError if key.Data == "" && key.KMS == "" && key.SecretRef == nil { errs = errs.Also(apis.ErrMissingOneOf("data", "kms", "secretref")) } if key.HashAlgorithm != "" { _, err := signaturealgo.HashAlgorithm(key.HashAlgorithm) if err != nil { errs = errs.Also(apis.ErrInvalidValue(key.HashAlgorithm, "hashAlgorithm")) } } if key.Data != "" { if key.KMS != "" || key.SecretRef != nil { errs = errs.Also(apis.ErrMultipleOneOf("data", "kms", "secretref")) } publicKey, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(key.Data)) if err != nil || publicKey == nil { errs = errs.Also(apis.ErrInvalidValue(key.Data, "data")) } } else if key.KMS != "" && key.SecretRef != nil { errs = errs.Also(apis.ErrMultipleOneOf("data", "kms", "secretref")) } if key.KMS != "" { errs = errs.Also(common.ValidateKMS(key.KMS).ViaField("kms")) } if key.SecretRef != nil && key.SecretRef.Namespace != "" && key.SecretRef.Namespace != system.Namespace() { errs = errs.Also(apis.ErrInvalidValue(key.SecretRef.Namespace, "secretref.namespace", "secretref.namespace is invalid. If set, it should use the same namespace where the policy-controller was deployed")) } return errs } func (keyless *KeylessRef) Validate(ctx context.Context) *apis.FieldError { var errs *apis.FieldError if keyless.URL == nil && keyless.CACert == nil { errs = errs.Also(apis.ErrMissingOneOf("url", "ca-cert")) } // TODO: Are these really mutually exclusive? if keyless.URL != nil && keyless.CACert != nil { errs = errs.Also(apis.ErrMultipleOneOf("url", "ca-cert")) } if keyless.CACert != nil { errs = errs.Also(keyless.DeepCopy().CACert.Validate(ctx).ViaField("ca-cert")) } // Check that identities is specified. if len(keyless.Identities) == 0 { errs = errs.Also(apis.ErrMissingField("identities")) } for i, identity := range keyless.Identities { errs = errs.Also(identity.Validate(ctx).ViaFieldIndex("identities", i)) } return errs } func (source *Source) Validate(_ context.Context) *apis.FieldError { var errs *apis.FieldError if source.OCI != "" { if err := common.ValidateOCI(source.OCI); err != nil { errs = errs.Also(apis.ErrInvalidValue(source.OCI, "oci", err.Error())) } } if len(source.SignaturePullSecrets) > 0 { for i, secret := range source.SignaturePullSecrets { if secret.Name == "" { errs = errs.Also(apis.ErrMissingField("name")).ViaFieldIndex("signaturePullSecrets", i) } } } return errs } func (a *Attestation) Validate(ctx context.Context) *apis.FieldError { var errs *apis.FieldError if a.Name == "" { errs = errs.Also(apis.ErrMissingField("name")) } switch { case a.PredicateType == "": // This is just straight up missing, so error out. errs = errs.Also(apis.ErrMissingField("predicateType")) case common.ValidPredicateTypes.Has(a.PredicateType): // Ok, it's a valid, deprecated short form. It's fine for now, but // should remove it soon because it is very error prone, so warn. errs = errs.Also(apis.ErrInvalidValue(a.PredicateType, "predicateType", "deprecated value, please use RFC 3986 conformant values").At(apis.WarningLevel)) default: // This could be a fully specified URL, so check for that here. if _, err := url.ParseRequestURI(a.PredicateType); err != nil { // This is fine for now, but should remove it soon because it is // very error prone. errs = errs.Also(apis.ErrInvalidValue(a.PredicateType, "predicateType", "deprecated value, please use RFC 3986 conformant values").At(apis.WarningLevel)) } } errs = errs.Also(a.Policy.Validate(ctx).ViaField("policy")) return errs } func (cmr *ConfigMapReference) Validate(_ context.Context) *apis.FieldError { var errs *apis.FieldError if cmr.Name == "" { errs = errs.Also(apis.ErrMissingField("name")) } if cmr.Key == "" { errs = errs.Also(apis.ErrMissingField("key")) } return errs } func (r *RemotePolicy) Validate(_ context.Context) *apis.FieldError { var errs *apis.FieldError urlObj := r.URL u, err := url.Parse(urlObj.String()) if err != nil || (err == nil && (u.Host == "" || u.Scheme == "" || u.Scheme != "https")) { errs = errs.Also(apis.ErrInvalidValue(r.URL.String(), "url", "url valid is invalid. host and https scheme are expected")) } if r.Sha256sum == "" { errs = errs.Also(apis.ErrMissingField("sha256sum")) } return errs } func (p *Policy) Validate(ctx context.Context) *apis.FieldError { if p == nil { return nil } var errs *apis.FieldError if p.Type != "cue" && p.Type != "rego" { errs = errs.Also(apis.ErrInvalidValue(p.Type, "type", "only [cue,rego] are supported at the moment")) } if p.Data == "" && p.ConfigMapRef == nil && p.Remote == nil { errs = errs.Also(apis.ErrMissingField("data", "configMapRef", "remote")) } if p.Data != "" && p.ConfigMapRef != nil && p.Remote != nil { errs = errs.Also(apis.ErrMultipleOneOf("data", "configMapRef", "remote")) } if (p.Data != "" && p.ConfigMapRef != nil) || (p.Data != "" && p.Remote != nil) || (p.ConfigMapRef != nil && p.Remote != nil) { errs = errs.Also(apis.ErrMultipleOneOf("data", "configMapRef", "remote")) } if p.Remote != nil { errs = errs.Also(p.Remote.Validate(ctx).ViaField("remote")) } if p.ConfigMapRef != nil { errs = errs.Also(p.ConfigMapRef.Validate(ctx).ViaField("configMapRef")) } if !apis.IsInSpec(ctx) && p.FetchConfigFile != nil { errs = errs.Also(apis.ErrDisallowedFields("fetchConfigFile")) } if !apis.IsInSpec(ctx) && p.IncludeSpec != nil { errs = errs.Also(apis.ErrDisallowedFields("includeSpec")) } if !apis.IsInSpec(ctx) && p.IncludeObjectMeta != nil { errs = errs.Also(apis.ErrDisallowedFields("includeObjectMeta")) } if !apis.IsInSpec(ctx) && p.IncludeTypeMeta != nil { errs = errs.Also(apis.ErrDisallowedFields("includeTypeMeta")) } // TODO(vaikas): How to validate the cue / rego bytes here (data). return errs } func (identity *Identity) Validate(_ context.Context) *apis.FieldError { var errs *apis.FieldError if identity.Issuer != "" && identity.IssuerRegExp != "" { errs = errs.Also(apis.ErrMultipleOneOf("issuer", "issuerRegExp")) } if identity.Subject != "" && identity.SubjectRegExp != "" { errs = errs.Also(apis.ErrMultipleOneOf("subject", "subjectRegExp")) } if identity.IssuerRegExp != "" { errs = errs.Also(ValidateRegex(identity.IssuerRegExp).ViaField("issuerRegExp")) } if identity.SubjectRegExp != "" { errs = errs.Also(ValidateRegex(identity.SubjectRegExp).ViaField("subjectRegExp")) } if identity.SubjectRegExp == "" && identity.Subject == "" { errs = errs.Also(apis.ErrMissingField("subject", "subjectRegExp")) } if identity.IssuerRegExp == "" && identity.Issuer == "" { errs = errs.Also(apis.ErrMissingField("issuer", "issuerRegExp")) } return errs } // ValidateGlob glob compilation by testing against empty string func ValidateGlob(g string) *apis.FieldError { if _, err := filepath.Match(g, ""); err != nil { return apis.ErrInvalidValue(g, apis.CurrentField, fmt.Sprintf("glob is invalid: %v", err)) } if _, err := glob.Compile(g); err != nil { return apis.ErrInvalidValue(g, apis.CurrentField, fmt.Sprintf("glob is invalid: %v", err)) } return nil } func ValidateRegex(regex string) *apis.FieldError { _, err := regexp.Compile(regex) if err != nil { return apis.ErrInvalidValue(regex, apis.CurrentField, fmt.Sprintf("regex is invalid: %v", err)) } return nil } ================================================ FILE: pkg/apis/policy/v1alpha1/clusterimagepolicy_validation_test.go ================================================ // 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. package v1alpha1 import ( "context" "os" "strings" "testing" "github.com/sigstore/policy-controller/pkg/apis/policy/common" "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/pkg/apis" "knative.dev/pkg/ptr" ) const validPublicKey = "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaEOVJCFtduYr3xqTxeRWSW32CY/s\nTBNZj4oIUPl8JvhVPJ1TKDPlNcuT4YphSt6t3yOmMvkdQbCj8broX6vijw==\n-----END PUBLIC KEY-----" func TestImagePatternValidation(t *testing.T) { tests := []struct { name string errorString string policy ClusterImagePolicy }{{ name: "Should fail when glob is not present", errorString: "missing field(s): spec.authorities, spec.images[0].glob", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ {}, }, }, }, }, { name: "Glob should fail with invalid glob", errorString: "invalid value: [: spec.images[0].glob\nglob is invalid: syntax error in pattern\nmissing field(s): spec.authorities", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "[", }, }, }, }, }, { name: "Glob should fail with invalid regexp", errorString: "invalid value: $FOO*: spec.images[0].glob\nglob is invalid: invalid glob \"$FOO*\"\nmissing field(s): spec.authorities", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "$FOO*", }, }, }, }, }, { name: "missing image and authorities in the spec", errorString: "missing field(s): spec.authorities, spec.images", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{}, }, }, { name: "Should fail when authority is missing", errorString: "missing field(s): spec.authorities", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "*", }, }, }, }, }, { name: "Should pass when glob is valid: %v", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "gcr.io/*", }, }, Authorities: []Authority{ { Key: &KeyRef{ KMS: "hashivault://key/path", }, }, }, }, }, }, { name: "Glob should pass with exact digest image", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "ghcr.io/foo@sha256:5504f2a95018e3d8a52d80d9e1a128c6ea337581808ff9fe96f5628ce2336350", }, }, Authorities: []Authority{ { Key: &KeyRef{ KMS: "hashivault://key/path", }, }, }, }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { err := test.policy.Validate(context.TODO()) validateError(t, test.errorString, "", err) }) } } func TestKeyValidation(t *testing.T) { os.Setenv("SYSTEM_NAMESPACE", "cosign-system") tests := []struct { name string errorString string policy ClusterImagePolicy }{{ name: "Should fail when key has multiple properties", errorString: "expected exactly one, got both: spec.authorities[0].key.data, spec.authorities[0].key.kms, spec.authorities[0].key.secretref", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "myglob", }, }, Authorities: []Authority{ { Key: &KeyRef{ Data: "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaEOVJCFtduYr3xqTxeRWSW32CY/s\nTBNZj4oIUPl8JvhVPJ1TKDPlNcuT4YphSt6t3yOmMvkdQbCj8broX6vijw==\n-----END PUBLIC KEY-----", KMS: "hashivault://key/path", }, }, }, }, }, }, { name: "Should fail when key has malformed pubkey data", errorString: "invalid value: ---some key data----: spec.authorities[0].key.data", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "myglob", }, }, Authorities: []Authority{ { Key: &KeyRef{ Data: "---some key data----", }, }, }, }, }, }, { name: "Should fail when key secretref has an invalid value for the namespace", errorString: "invalid value: invalid: spec.authorities[0].key.secretref.namespace\nsecretref.namespace is invalid. If set, it should use the same namespace where the policy-controller was deployed", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "myglob", }, }, Authorities: []Authority{ { Key: &KeyRef{ SecretRef: &v1.SecretReference{ Name: "test", Namespace: "invalid", }, }, }, }, }, }, }, { name: "Should fail when key is empty", errorString: "expected exactly one, got neither: spec.authorities[0].key.data, spec.authorities[0].key.kms, spec.authorities[0].key.secretref", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "myglob*", }, }, Authorities: []Authority{ { Key: &KeyRef{}, }, }, }, }, }, { name: "Should pass when key has only one property: %v", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "yepanotherglob", }, }, Authorities: []Authority{ { Key: &KeyRef{ KMS: "hashivault://key/path", }, }, }, }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { err := test.policy.Validate(context.TODO()) validateError(t, test.errorString, "", err) }) } } func TestKeylessValidation(t *testing.T) { tests := []struct { name string errorString string policy ClusterImagePolicy }{{ name: "Should fail when keyless is empty", errorString: "expected exactly one, got neither: spec.authorities[0].keyless.ca-cert, spec.authorities[0].keyless.url\nmissing field(s): spec.authorities[0].keyless.identities", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{}, }, }, }, }, }, { name: "Should fail when keyless has multiple properties", errorString: "expected exactly one, got both: spec.authorities[0].keyless.ca-cert, spec.authorities[0].keyless.url\nmissing field(s): spec.authorities[0].keyless.identities", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, CACert: &KeyRef{ Data: validPublicKey, }, }, }, }, }, }, }, { name: "Should warn when valid keyless ref is specified, but no identities given", errorString: "missing field(s): spec.authorities[0].keyless.identities", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, }, }, }, }, }, }, { name: "Should pass when valid keyless ref is specified", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{ { Subject: "somesubject", Issuer: "someissuer", }, }, }, }, }, }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { err := test.policy.Validate(context.TODO()) validateError(t, test.errorString, "", err) }) } } func TestStaticValidation(t *testing.T) { tests := []struct { name string errorString string policy ClusterImagePolicy }{{ name: "Should fail when static is empty", errorString: "missing field(s): spec.authorities[0].static.action", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Static: &StaticRef{}, }, }, }, }, }, { name: "Should fail when action is invalid", errorString: "invalid value: garbage: spec.authorities[0].static.action\nunsupported action", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Static: &StaticRef{Action: "garbage"}, }, }, }, }, }, { name: "Works with pass", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Static: &StaticRef{Action: "pass"}, }, }, }, }, }, { name: "Works with pass, and Spec.Policy.FetchConfigFile", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Static: &StaticRef{Action: "pass"}, }, }, Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, FetchConfigFile: ptr.Bool(true), }, }, }, }, { name: "Works with pass, and Spec.Policy.IncludeSpec", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Static: &StaticRef{Action: "pass"}, }, }, Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, IncludeSpec: ptr.Bool(true), }, }, }, }, { name: "Works with pass, and Spec.Policy.IncludeObjectMeta", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Static: &StaticRef{Action: "pass"}, }, }, Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, IncludeObjectMeta: ptr.Bool(true), }, }, }, }, { name: "Works with pass, and Spec.Policy.IncludeTypeMeta", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Static: &StaticRef{Action: "pass"}, }, }, Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, IncludeTypeMeta: ptr.Bool(true), }, }, }, }, { name: "Works with fail", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Static: &StaticRef{Action: "fail"}, }, }, }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { err := test.policy.Validate(context.TODO()) validateError(t, test.errorString, "", err) }) } } func TestModeValidation(t *testing.T) { tests := []struct { name string errorString string mode string }{{ name: "Should work when mode is empty", mode: "", }, { name: "Should work with mode enforce", mode: "enforce", }, { name: "Should work with mode warn", mode: "warn", }, { name: "Should not work with mode garbage", mode: "garbage", errorString: "invalid value: garbage: spec.mode\nunsupported mode", }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { policy := ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "globbityglob"}}, Authorities: []Authority{{Static: &StaticRef{Action: "pass"}}}, Mode: test.mode, }, } err := policy.Validate(context.TODO()) validateError(t, test.errorString, "", err) }) } } func TestAuthoritiesValidation(t *testing.T) { tests := []struct { name string errorString string warnString string policy ClusterImagePolicy }{{ name: "Should fail when authority is empty", errorString: "expected exactly one, got neither: spec.authorities[0].key, spec.authorities[0].keyless, spec.authorities[0].static", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ {}, }, }, }, }, { name: "Should fail when key/keyless specified", errorString: "expected exactly one, got both: spec.authorities[0].key, spec.authorities[0].keyless, spec.authorities[0].static", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Key: &KeyRef{Data: validPublicKey}, Keyless: &KeylessRef{URL: apis.HTTPS("fulcio.sigstore.dev")}, }, }, }, }, }, { name: "Should fail when key/static specified", errorString: "expected exactly one, got both: spec.authorities[0].key, spec.authorities[0].keyless, spec.authorities[0].static", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Key: &KeyRef{Data: validPublicKey}, Static: &StaticRef{Action: "pass"}, }, }, }, }, }, { name: "Should fail when keyless/static specified", errorString: "expected exactly one, got both: spec.authorities[0].key, spec.authorities[0].keyless, spec.authorities[0].static", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Static: &StaticRef{Action: "fail"}, Keyless: &KeylessRef{URL: apis.HTTPS("fulcio.sigstore.dev")}, }, }, }, }, }, { name: "Should fail when key/keyless/static specified", errorString: "expected exactly one, got both: spec.authorities[0].key, spec.authorities[0].keyless, spec.authorities[0].static", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Key: &KeyRef{Data: validPublicKey}, Keyless: &KeylessRef{URL: apis.HTTPS("fulcio.sigstore.dev")}, Static: &StaticRef{Action: "fail"}, }, }, }, }, }, { name: "Should fail when static and sources,attestations, and ctlog is specified, warn about legacy short predicate type", errorString: "expected exactly one, got both: spec.authorities[0].attestations, spec.authorities[0].ctlog, spec.authorities[0].source, spec.authorities[0].static", warnString: "invalid value: vuln: spec.authorities[0].attestations.predicateType\ndeprecated value, please use RFC 3986 conformant values", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Static: &StaticRef{Action: "fail"}, Attestations: []Attestation{{Name: "first", PredicateType: "vuln"}}, Sources: []Source{ { OCI: "registry1", SignaturePullSecrets: []v1.LocalObjectReference{ {Name: "placeholder"}, }, }, }, CTLog: &TLog{}, }, }, }, }, }, { name: "Should fail when authorities is empty", errorString: "missing field(s): spec.authorities", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{}, }, }, }, { name: "Should pass when source oci is present", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Sources: []Source{{OCI: "registry.example.com"}}, }, }, }, }, }, { name: "Should fail with invalid AWS KMS for Keyful", errorString: "invalid value: awskms://localhost:8888/arn:butnotvalid: spec.authorities[0].key.kms\nkms key should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "awskms://localhost:8888/arn:butnotvalid"}, Sources: []Source{{OCI: "registry.example.com"}}, }, }, }, }, }, { name: "Should fail with invalid kms prefix", errorString: "invalid value: fookms://localhost:8888/xpa:butnotvalid: spec.authorities[0].key.kms\nmalformed KMS format, should be prefixed by any of the supported providers: [awskms:// azurekms:// hashivault:// gcpkms://]", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "fookms://localhost:8888/xpa:butnotvalid"}, Sources: []Source{{OCI: "registry.example.com"}}, }, }, }, }, }, { name: "Should fail with invalid AWS KMS for Keyful", errorString: "invalid value: awskms://localhost:8888/arn:butnotvalid: spec.authorities[0].key.kms\nkms key should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "awskms://localhost:8888/arn:butnotvalid"}, Sources: []Source{{OCI: "registry.example.com"}}, }, }, }, }, }, { name: "Should fail with invalid OCI value", errorString: "invalid value: registry.example.com/repo/*: spec.authorities[0].source[0].oci\nrepository can only contain the characters `abcdefghijklmnopqrstuvwxyz0123456789_-./`: repo/*", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Sources: []Source{{OCI: "registry.example.com/repo/*"}}, }, }, }, }, }, { name: "Should fail with invalid OCI value usign wrong characters", errorString: "invalid value: re@gistry/reponame: spec.authorities[0].source[0].oci\nregistries must be valid RFC 3986 URI authorities: re@gistry/reponame", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Sources: []Source{{OCI: "re@gistry/reponame"}}, }, }, }, }, }, { name: "Should pass with valid OCI repository name", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Sources: []Source{{OCI: "gcr.io/google.com/project/hello-world"}}, }, }, }, }, }, { name: "Should pass with valid OCI repository name", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Sources: []Source{{OCI: "registry.example.com/repository"}}, }, }, }, }, }, { name: "Should fail with invalid AWS KMS for Keyless", errorString: "invalid value: awskms://localhost:8888/arn:butnotvalid: spec.authorities[0].keyless.ca-cert.kms\nkms key should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)\nmissing field(s): spec.authorities[0].keyless.identities", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Keyless: &KeylessRef{CACert: &KeyRef{KMS: "awskms://localhost:8888/arn:butnotvalid"}}, }, }, }, }, }, { name: "Should pass with single source oci is present", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Sources: []Source{ {OCI: "registry1"}, }, }, }, }, }, }, { name: "Should fail with multiple source oci is present", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Sources: []Source{ {OCI: "registry1"}, {OCI: "registry2"}, }, }, }, }, }, errorString: "invalid value: source: spec.authorities[0].source\nonly single source is supported", }, { name: "Should pass with attestations present", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Attestations: []Attestation{ {Name: "first", PredicateType: "https://cosign.sigstore.dev/attestation/vuln/v1"}, {Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, }, }, }, }, }, }, }, }, { name: "Should fail with attestations policy specifying fetchConfigFile", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Attestations: []Attestation{ {Name: "first", PredicateType: "https://cosign.sigstore.dev/attestation/vuln/v1"}, {Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, FetchConfigFile: ptr.Bool(true), }, }, }, }, }, }, }, errorString: "must not set the field(s): spec.authorities[0].attestations.policy.fetchConfigFile", }, { name: "Should fail with attestations policy specifying includeSpec", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Attestations: []Attestation{ {Name: "first", PredicateType: "https://cosign.sigstore.dev/attestation/vuln/v1"}, {Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, IncludeSpec: ptr.Bool(true), }, }, }, }, }, }, }, errorString: "must not set the field(s): spec.authorities[0].attestations.policy.includeSpec", }, { name: "Should fail with attestations policy specifying includeObjectMeta", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Attestations: []Attestation{ {Name: "first", PredicateType: "https://cosign.sigstore.dev/attestation/vuln/v1"}, {Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, IncludeObjectMeta: ptr.Bool(true), }, }, }, }, }, }, }, errorString: "must not set the field(s): spec.authorities[0].attestations.policy.includeObjectMeta", }, { name: "Should fail with attestations policy specifying includeTypeMeta", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Attestations: []Attestation{ {Name: "first", PredicateType: "https://cosign.sigstore.dev/attestation/vuln/v1"}, {Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, IncludeTypeMeta: ptr.Bool(true), }, }, }, }, }, }, }, errorString: "must not set the field(s): spec.authorities[0].attestations.policy.includeTypeMeta", }, { name: "Should fail with signaturePullSecret name empty", errorString: "missing field(s): spec.authorities[0].source[0].signaturePullSecrets[0].name", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Sources: []Source{ { OCI: "registry1", SignaturePullSecrets: []v1.LocalObjectReference{ {Name: ""}, }, }, }, }, }, }, }, }, { name: "Should pass with signaturePullSecret name filled", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Sources: []Source{ { OCI: "registry1", SignaturePullSecrets: []v1.LocalObjectReference{ {Name: "testPullSecrets"}, }, }, }, }, }, }, }, }, { name: "Should pass when source oci is empty", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Sources: []Source{{OCI: ""}}, }, }, }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { err := test.policy.Validate(context.TODO()) validateError(t, test.errorString, test.warnString, err) }) } } func TestAttestationsValidation(t *testing.T) { tests := []struct { name string errorString string warnString string attestation Attestation }{{ name: "https://cosign.sigstore.dev/attestation/vuln/v1", attestation: Attestation{Name: "first", PredicateType: "https://cosign.sigstore.dev/attestation/vuln/v1"}, }, { name: "fully specified URL", attestation: Attestation{Name: "fullyspecified", PredicateType: "https://cyclonedx.org/schema"}, }, { name: "missing name", attestation: Attestation{PredicateType: "https://cosign.sigstore.dev/attestation/vuln/v1"}, errorString: "missing field(s): name", }, { name: "missing predicatetype", attestation: Attestation{Name: "first"}, errorString: "missing field(s): predicateType", }, { name: "invalid predicatetype", attestation: Attestation{Name: "first", PredicateType: "notsupported"}, warnString: "invalid value: notsupported: predicateType\ndeprecated value, please use RFC 3986 conformant values", }, { name: "custom with invalid policy type", attestation: Attestation{Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "not-cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, }, }, errorString: "invalid value: not-cue: policy.type\nonly [cue,rego] are supported at the moment", }, { name: "custom with missing policy data and configMapRef", attestation: Attestation{Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", }, }, errorString: "missing field(s): policy.configMapRef, policy.data, policy.remote", }, { name: "custom with both policy data and configMapRef", attestation: Attestation{Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, ConfigMapRef: &ConfigMapReference{ Name: "cmname", Key: "keyname", }, }, }, errorString: "expected exactly one, got both: policy.configMapRef, policy.data, policy.remote", }, { name: "custom with both policy data, url and configMapRef", attestation: Attestation{Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, ConfigMapRef: &ConfigMapReference{ Name: "cmname", Key: "keyname", }, Remote: &RemotePolicy{ URL: *apis.HTTPS("example.com"), Sha256sum: "123123123", }, }, }, errorString: "expected exactly one, got both: policy.configMapRef, policy.data, policy.remote", }, { name: "custom with both policy url", attestation: Attestation{Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", Remote: &RemotePolicy{ URL: *apis.HTTPS("example.com"), Sha256sum: "123123123", }, }, }, }, { name: "custom with invalid policy url scheme", attestation: Attestation{Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", Remote: &RemotePolicy{ URL: *apis.HTTP("example.com"), Sha256sum: "123123123", }, }, }, errorString: "invalid value: http://example.com: policy.remote.url\nurl valid is invalid. host and https scheme are expected", }, { name: "custom with invalid configMapRef, missing key", attestation: Attestation{Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", ConfigMapRef: &ConfigMapReference{ Name: "cmname", }, }, }, errorString: "missing field(s): policy.configMapRef.key", }, { name: "custom with policy", attestation: Attestation{Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { err := test.attestation.Validate(context.TODO()) validateError(t, test.errorString, test.warnString, err) }) } } func TestIdentitiesValidation(t *testing.T) { tests := []struct { name string errorString string policy ClusterImagePolicy }{{ name: "Should pass with identities", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{{SubjectRegExp: ".*subject.*", IssuerRegExp: ".*issuer.*"}}, }, }, }, }, }, }, { name: "Should warn when identities fields are empty", errorString: "missing field(s): spec.authorities[0].keyless.identities[0].issuer, spec.authorities[0].keyless.identities[0].issuerRegExp, spec.authorities[0].keyless.identities[0].subject, spec.authorities[0].keyless.identities[0].subjectRegExp", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{{Issuer: ""}}, }, }, }, }, }, }, { name: "Should fail with both issuer and issuerRegExp", errorString: "expected exactly one, got both: spec.authorities[0].keyless.identities[0].issuer, spec.authorities[0].keyless.identities[0].issuerRegExp", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{{Issuer: "issuer", IssuerRegExp: "issuerregexp", Subject: "subject"}}, }, }, }, }, }, }, { name: "Should fail with both subject and subjectRegExp", errorString: "expected exactly one, got both: spec.authorities[0].keyless.identities[0].subject, spec.authorities[0].keyless.identities[0].subjectRegExp", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{{Subject: "subject", SubjectRegExp: "subjectregexp", Issuer: "issuer"}}, }, }, }, }, }, }, { name: "Should fail when issuer has invalid regex", errorString: "invalid value: ****: spec.authorities[0].keyless.identities[0].issuerRegExp\nregex is invalid: error parsing regexp: missing argument to repetition operator: `*`", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{{IssuerRegExp: "****", Subject: "subject"}}, }, }, }, }, }, }, { name: "Should warn when issuer or issuerRegExp is missing", errorString: "missing field(s): spec.authorities[0].keyless.identities[0].issuer, spec.authorities[0].keyless.identities[0].issuerRegExp", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{{Subject: "subject"}}, }, }, }, }, }, }, { name: "Should warn when subject or subjectRegExp is missing", errorString: "missing field(s): spec.authorities[0].keyless.identities[0].subject, spec.authorities[0].keyless.identities[0].subjectRegExp", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{{Issuer: "issuer"}}, }, }, }, }, }, }, { name: "Should fail when subject has invalid regex", errorString: "invalid value: ****: spec.authorities[0].keyless.identities[0].subjectRegExp\nregex is invalid: error parsing regexp: missing argument to repetition operator: `*`", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{{Issuer: "issuer", SubjectRegExp: "****"}}, }, }, }, }, }, }, { name: "Should pass when subject and issuer have valid regex", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{{SubjectRegExp: ".*subject.*", IssuerRegExp: ".*issuer.*"}}, }, }, }, }, }, }, { name: "Should pass when identities is valid", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{ { Issuer: "some issuer", Subject: "some subject", }, }, }, }, }, }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { err := test.policy.Validate(context.TODO()) validateError(t, test.errorString, "", err) }) } } func TestAWSKMSValidation(t *testing.T) { // Note the error messages betweeen the kms / cacert validation is // identical, with the only difference being `kms` or `ca-cert.kms`. Reason // for the ca-cert.kms is because it's embedded within the ca-cert that // we pass in. So we put a KMSORCACERT into the err string that we then // replace based on the tests so we don't have to write identical tests // for both of them. tests := []struct { name string expectErr bool errorString string kms string }{{ name: "malformed, only 2 slashes ", expectErr: true, errorString: "invalid value: awskms://1234abcd-12ab-34cd-56ef-1234567890ab: KMSORCACERT\nmalformed AWS KMS format 'awskms://$ENDPOINT/$KEYID', should be conformant with KMS standard documented here: https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id", kms: "awskms://1234abcd-12ab-34cd-56ef-1234567890ab", }, { name: "fails with invalid host", expectErr: true, errorString: "invalid value: awskms://localhost:::4566/alias/exampleAlias: KMSORCACERT\nmalformed endpoint: address localhost:::4566: too many colons in address", kms: "awskms://localhost:::4566/alias/exampleAlias", }, { name: "fails with non-arn alias", expectErr: true, errorString: "invalid value: awskms://localhost:4566/alias/exampleAlias: KMSORCACERT\nfailed to parse either key or alias arn: arn: invalid prefix", kms: "awskms://localhost:4566/alias/exampleAlias", }, { name: "Should fail when arn is invalid", expectErr: true, errorString: "invalid value: awskms://localhost:4566/arn:sonotvalid: KMSORCACERT\nkms key should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)", kms: "awskms://localhost:4566/arn:sonotvalid", }, { name: "Should fail with key is invalid", expectErr: true, errorString: "invalid value: awskms://arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab: KMSORCACERT\nkms key should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)", kms: "awskms://arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", }, { name: "works with valid arn key and endpoint", kms: "awskms://localhost:4566/arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", }, { name: "works with valid arn key and no endpoint", kms: "awskms:///arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", }, { name: "works with valid arn alias and endpoint", kms: "awskms://localhost:4566/arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias", }, { name: "works with valid arn alias and no endpoint", kms: "awskms:///arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias", }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { // First test with KeyRef keyRef := KeyRef{KMS: test.kms} err := keyRef.Validate(context.TODO()) kmsErrString := strings.Replace(test.errorString, "KMSORCACERT", "kms", 1) validateError(t, kmsErrString, "", err) // Then with Keyless with CACert as KeyRef keylessRef := KeylessRef{CACert: &keyRef, Identities: []Identity{{Subject: "testsubject", Issuer: "testIssuer"}}} err = keylessRef.Validate(context.TODO()) caCertErrString := strings.Replace(test.errorString, "KMSORCACERT", "ca-cert.kms", 1) validateError(t, caCertErrString, "", err) }) } } func TestMatchValidation(t *testing.T) { // Add a "supported" resource name that we'll use to test things. common.ValidResourceNames.Insert("supported") tests := []struct { name string errorString string policy ClusterImagePolicy }{{ name: "Should pass with identities", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{{SubjectRegExp: ".*subject.*", IssuerRegExp: ".*issuer.*"}}, }, }, }, }, }, }, { name: "Should pass with match label selector", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Match: []MatchResource{ { GroupVersionResource: metav1.GroupVersionResource{ Group: "apps", Version: "v1", Resource: "supported", }, ResourceSelector: &metav1.LabelSelector{ MatchLabels: map[string]string{"a": "b", "c": "d"}, }, }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{ { Issuer: "some issuer", Subject: "some subject", }, }, }, }, }, }, }, }, { name: "Should pass with match resource types", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Match: []MatchResource{ { GroupVersionResource: metav1.GroupVersionResource{ Group: "apps", Version: "v1", Resource: "supported", }, }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, InsecureIgnoreSCT: ptr.Bool(true), Identities: []Identity{ { Issuer: "some issuer", Subject: "some subject", }, }, }, }, }, }, }, }, { name: "Should fail with invalid match resource type", errorString: "invalid value: myobject: spec.match[0].resource\nunsupported resource name", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Match: []MatchResource{ { GroupVersionResource: metav1.GroupVersionResource{ Group: "", Version: "v1", Resource: "myobject", }, }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{ { Issuer: "some issuer", Subject: "some subject", }, }, }, }, }, }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { err := test.policy.Validate(context.TODO()) validateError(t, test.errorString, "", err) }) } } // validateError checks the given error against wanted error/warning strings // if either is "" then it's assume an error/warning is not wanted and if // one is given, will error. // nolint since currently we do not have warnings we expect, but having this // around makes it easier to add warning validations in the future. // //nolint:all func validateError(t *testing.T, wantErrStr, wantWarnStr string, fe *apis.FieldError) { t.Helper() // Grab warning and check it first warnFE := fe.Filter(apis.WarningLevel) if wantWarnStr != "" { require.NotNil(t, warnFE) require.EqualError(t, warnFE, wantWarnStr) } else { require.Nil(t, warnFE) } // Then grab error and check it errFE := fe.Filter(apis.ErrorLevel) if wantErrStr != "" { require.NotNil(t, errFE) require.EqualError(t, errFE, wantErrStr) } else { require.Nil(t, errFE) } } func TestIgnoreStatusUpdates(t *testing.T) { cip := &ClusterImagePolicy{Spec: ClusterImagePolicySpec{Images: []ImagePattern{{Glob: ""}}}} if err := cip.Validate(apis.WithinSubResourceUpdate(context.Background(), &cip, "status")); err != nil { t.Errorf("Failed to update status on invalid resource: %v", err) } } ================================================ FILE: pkg/apis/policy/v1alpha1/doc.go ================================================ // 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. // +k8s:deepcopy-gen=package // +groupName=policy.sigstore.dev package v1alpha1 ================================================ FILE: pkg/apis/policy/v1alpha1/register.go ================================================ // 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. package v1alpha1 import ( policy "github.com/sigstore/policy-controller/pkg/apis/policy" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" ) // SchemeGroupVersion is group version used to register these objects var SchemeGroupVersion = schema.GroupVersion{Group: policy.GroupName, Version: "v1alpha1"} // Kind takes an unqualified kind and returns back a Group qualified GroupKind func Kind(kind string) schema.GroupKind { return SchemeGroupVersion.WithKind(kind).GroupKind() } // Resource takes an unqualified resource and returns a Group qualified GroupResource func Resource(resource string) schema.GroupResource { return SchemeGroupVersion.WithResource(resource).GroupResource() } var ( // SchemeBuilder builds a scheme with the types known to the package. SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) // AddToScheme adds the types known to this package to an existing schema. AddToScheme = SchemeBuilder.AddToScheme ) // Adds the list of known types to Scheme. func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &ClusterImagePolicy{}, &ClusterImagePolicyList{}, &TrustRoot{}, &TrustRootList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil } ================================================ FILE: pkg/apis/policy/v1alpha1/trustroot_defaults.go ================================================ // 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. package v1alpha1 import "context" // SetDefaults implements apis.Defaultable func (tr *TrustRoot) SetDefaults(ctx context.Context) { tr.Spec.SetDefaults(ctx) } func (spec *TrustRootSpec) SetDefaults(_ context.Context) { if spec.Repository != nil && spec.Repository.Targets == "" { spec.Repository.Targets = "targets" } if spec.Remote != nil && spec.Remote.Targets == "" { spec.Remote.Targets = "targets" } } ================================================ FILE: pkg/apis/policy/v1alpha1/trustroot_defaults_test.go ================================================ // 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. package v1alpha1 import ( "context" "testing" ) const defaultTargets = "targets" func TestTargetsDefaulting(t *testing.T) { tests := []struct { in *TrustRoot wantRepositoryTarget string wantRemoteTarget string }{ {in: trustrootWithTargets("", ""), wantRepositoryTarget: defaultTargets, wantRemoteTarget: defaultTargets, }, {in: trustrootWithTargets("foo", ""), wantRepositoryTarget: "foo", wantRemoteTarget: defaultTargets, }, {in: trustrootWithTargets("", "bar"), wantRepositoryTarget: defaultTargets, wantRemoteTarget: "bar", }, {in: trustrootWithTargets("foo", "bar"), wantRepositoryTarget: "foo", wantRemoteTarget: "bar", }} for _, tc := range tests { tc.in.SetDefaults(context.TODO()) if tc.wantRemoteTarget != tc.in.Spec.Remote.Targets { t.Errorf("Wanted remote target: %s got: %s", tc.wantRemoteTarget, tc.in.Spec.Remote.Targets) } if tc.wantRepositoryTarget != tc.in.Spec.Repository.Targets { t.Errorf("Wanted remote target: %s got: %s", tc.wantRepositoryTarget, tc.in.Spec.Repository.Targets) } } } func trustrootWithTargets(repoTargets, remoteTargets string) *TrustRoot { return &TrustRoot{ Spec: TrustRootSpec{ Repository: &Repository{Targets: repoTargets}, Remote: &Remote{Targets: remoteTargets}, }, } } ================================================ FILE: pkg/apis/policy/v1alpha1/trustroot_lifecycle.go ================================================ // Copyright 2023 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. package v1alpha1 import ( "knative.dev/pkg/apis" ) var trCondSet = apis.NewLivingConditionSet( TrustRootConditionKeysInlined, TrustRootConditionCMUpdated, ) // GetConditionSet retrieves the condition set for this resource. // Implements the KRShaped interface. func (*TrustRoot) GetConditionSet() apis.ConditionSet { return trCondSet } // IsReady returns if the TrustRoot was compiled successfully to // ConfigMap. func (tr *TrustRoot) IsReady() bool { ts := tr.Status return ts.ObservedGeneration == tr.Generation && ts.GetCondition(TrustRootConditionReady).IsTrue() } // IsFailed returns true if the resource has observed // the latest generation and ready is false. func (tr *TrustRoot) IsFailed() bool { ts := tr.Status return ts.ObservedGeneration == tr.Generation && ts.GetCondition(TrustRootConditionReady).IsFalse() } // InitializeConditions sets the initial values to the conditions. func (ts *TrustRootStatus) InitializeConditions() { trCondSet.Manage(ts).InitializeConditions() } // MarkInlineKeysFailed surfaces a failure that we were unable to inline // the keys (from secrets or from KMS). func (ts *TrustRootStatus) MarkInlineKeysFailed(msg string) { cipCondSet.Manage(ts).MarkFalse(TrustRootConditionKeysInlined, inlineKeysFailedReason, msg) } // MarkInlineKeysOk marks the status saying that the inlining of the keys // had no errors. func (ts *TrustRootStatus) MarkInlineKeysOk() { cipCondSet.Manage(ts).MarkTrue(TrustRootConditionKeysInlined) } // MarkCMUpdateFailed surfaces a failure that we were unable to reflect the // TrustRoot into the compiled ConfigMap. func (ts *TrustRootStatus) MarkCMUpdateFailed(msg string) { trCondSet.Manage(ts).MarkFalse(TrustRootConditionCMUpdated, updateCMFailedReason, msg) } // MarkCMUpdated marks the status saying that the ConfigMap has been updated. func (ts *TrustRootStatus) MarkCMUpdatedOK() { trCondSet.Manage(ts).MarkTrue(TrustRootConditionCMUpdated) } ================================================ FILE: pkg/apis/policy/v1alpha1/trustroot_types.go ================================================ // 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. package v1alpha1 import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" "knative.dev/pkg/kmeta" ) // TrustRoot defines the keys and certificates that are trusted for // validating against. These can be specified as TUF Roots, serialized TUF // repository (for air-gap scenarios), as well as serialized keys/certificates, // for bring your own keys/certs. // // +genclient // +genclient:nonNamespaced // +genreconciler:krshapedlogic=true // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type TrustRoot struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata"` // Spec is the definition for a trust root. This is either a TUF root and // remote or local repository. You can also bring your own keys/certs here. Spec TrustRootSpec `json:"spec"` // Status represents the current state of the TrustRoot. // This data may be out of date. // +optional Status TrustRootStatus `json:"status,omitempty"` } var ( _ apis.Validatable = (*TrustRoot)(nil) _ apis.Defaultable = (*TrustRoot)(nil) _ kmeta.OwnerRefable = (*TrustRoot)(nil) // Check that the type conforms to the duck Knative Resource shape. _ duckv1.KRShaped = (*TrustRoot)(nil) ) const ( // TrustRootConditionReady is set when the TrustRoot has been // compiled into the underlying ConfigMap properly. TrustRootConditionReady = apis.ConditionReady // TrustRootConditionKeysInlined is set to True when keys have been either // verified, fetched and verified and inlined into the intermediate // representation usable for validation. TrustRootConditionKeysInlined apis.ConditionType = "KeysInlined" // TrustRootConditionCMUpdated is set to True when the inline representation // has been successfully added to the ConfigMap holding all the TrustRoots. TrustRootConditionCMUpdated apis.ConditionType = "ConfigMapUpdated" ) // GetGroupVersionKind implements kmeta.OwnerRefable func (tr *TrustRoot) GetGroupVersionKind() schema.GroupVersionKind { return SchemeGroupVersion.WithKind("TrustRoot") } // TrustRootSpec defines a trusted Root. This is typically either a TUF Root // or a bring your own keys variation. // It specifies either: // root.json and remote // or // fully gzipped / tarred directory containing root and metadata directories // or // serialized keys / certificate chains (bring your own keys). type TrustRootSpec struct { // Remote specifies initial root of trust & remote mirror. // +optional Remote *Remote `json:"remote,omitempty"` // Repository contains the serialized TUF remote repository. // +optional Repository *Repository `json:"repository,omitempty"` // SigstoreKeys contains the serialized keys. // +optional SigstoreKeys *SigstoreKeys `json:"sigstoreKeys,omitempty"` } // Remote specifies the TUF with trusted initial root and remote mirror where // to fetch updates from. type Remote struct { // Root is the base64 encoded, json trusted initial root. Root []byte `json:"root"` // Mirror is the remote mirror, for example: // https://tuf-repo-cdn.sigstore.dev Mirror apis.URL `json:"mirror"` // Targets is where the targets live off of the root of the Remote // If not specified 'targets' is defaulted. // +optional Targets string `json:"targets,omitempty"` // TrustedRootTarget is the name of the target containing the JSON trusted // root. If not specified, `trusted_root.json` is used. // +optional TrustedRootTarget string `json:"trustedRootTarget,omitempty"` } // Repository specifies an airgapped TUF. Specifies the trusted initial root as // well as a serialized repository. type Repository struct { // Root is the base64 encoded, json trusted initial root. Root []byte `json:"root"` // MirrorFS is the base64 tarred, gzipped, and base64 encoded remote // repository that can be used for example in air-gap environments. Will // not make outbound network connections, and must then be kept up to date // in some other manner. // The repository must contain metadata as well as targets. MirrorFS []byte `json:"mirrorFS"` // Targets is where the targets live off of the root of the Repository // above. If not specified 'targets' is defaulted. // +optional Targets string `json:"targets,omitempty"` // TrustedRootTarget is the name of the target containing the JSON trusted // root. If not specified, `trusted_root.json` is used. // +optional TrustedRootTarget string `json:"trustedRootTarget,omitempty"` } // TransparencyLogInstance describes the immutable parameters from a // transparency log. // See https://www.rfc-editor.org/rfc/rfc9162.html#name-log-parameters // for more details. // The incluced parameters are the minimal set required to identify a log, // and verify an inclusion promise. type TransparencyLogInstance struct { // The base URL which can be used for URLs for clients. BaseURL apis.URL `json:"baseURL"` // / The hash algorithm used for the Merkle Tree HashAlgorithm string `json:"hashAlgorithm"` // PEM encoded public key PublicKey []byte `json:"publicKey"` } type DistinguishedName struct { Organization string `json:"organization"` CommonName string `json:"commonName"` } type CertificateAuthority struct { // The root certificate MUST be self-signed, and so the subject and // issuer are the same. Subject DistinguishedName `json:"subject"` // The URI at which the CA can be accessed. URI apis.URL `json:"uri"` // The certificate chain for this CA in PEM format. Last entry in this // chain is the Root certificate. CertChain []byte `json:"certChain"` // TODO(vaikas): How to best represent this // The time the *entire* chain was valid. This is at max the // longest interval when *all* certificates in the chain where valid, // but it MAY be shorter. // dev.sigstore.common.v1.TimeRange valid_for = 4; } // SigstoreKeys contains all the necessary Keys and Certificates for validating // against a specific instance of Sigstore. This is used for bringing your own // trusted keys/certs. // TODO(vaikas): See about replacing these with the protos here once they land // and see how easy it is to replace with protos instead of our custom defs // above. // https://github.com/sigstore/protobuf-specs/pull/5 // And in particular: https://github.com/sigstore/protobuf-specs/pull/5/files#diff-b1f89b7fd3eb27b519380b092a2416f893a96fbba3f8c90cfa767e7687383ad4R70 // Well, not the multi-root, but one instance of that is exactly the // SigstoreKeys. type SigstoreKeys struct { // Trusted certificate authorities (e.g Fulcio). CertificateAuthorities []CertificateAuthority `json:"certificateAuthorities"` // Rekor log specifications // +optional TLogs []TransparencyLogInstance `json:"tLogs,omitempty"` // Certificate Transparency Log // +optional CTLogs []TransparencyLogInstance `json:"ctLogs,omitempty"` // Trusted timestamping authorities // +optional TimeStampAuthorities []CertificateAuthority `json:"timestampAuthorities,omitempty"` } // TrustRootStatus represents the current state of a TrustRoot. type TrustRootStatus struct { // inherits duck/v1 Status, which currently provides: // * ObservedGeneration - the 'Generation' of the Broker that was last processed by the controller. // * Conditions - the latest available observations of a resource's current state. duckv1.Status `json:",inline"` } // GetStatus retrieves the status of the TrustRoot. // Implements the KRShaped interface. func (tr *TrustRoot) GetStatus() *duckv1.Status { return &tr.Status.Status } // TrustRootList is a list of TrustRoot resources // // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type TrustRootList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata"` Items []TrustRoot `json:"items"` } ================================================ FILE: pkg/apis/policy/v1alpha1/trustroot_validation.go ================================================ // 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. package v1alpha1 import ( "bytes" "context" "crypto/x509" "encoding/json" "github.com/sigstore/policy-controller/pkg/tuf" "github.com/sigstore/sigstore/pkg/cryptoutils" "knative.dev/pkg/apis" "knative.dev/pkg/logging" ) // By default the TUF repo contains this prefix, so if it's there, remove // it. const DefaultTUFRepoPrefix = "/repository/" // Validate implements apis.Validatable func (tr *TrustRoot) Validate(ctx context.Context) *apis.FieldError { // If we're doing status updates, do not validate the spec. if apis.IsInStatusUpdate(ctx) { return nil } return tr.Spec.Validate(ctx).ViaField("spec") } func (spec *TrustRootSpec) Validate(ctx context.Context) (errors *apis.FieldError) { if spec.Repository == nil && spec.Remote == nil && spec.SigstoreKeys == nil { return apis.ErrMissingOneOf("repository", "remote", "sigstoreKeys") } if spec.Repository != nil { if spec.Remote != nil || spec.SigstoreKeys != nil { return apis.ErrMultipleOneOf("repository", "remote", "sigstoreKeys") } return spec.Repository.Validate(ctx).ViaField("repository") } if spec.Remote != nil { if spec.Repository != nil || spec.SigstoreKeys != nil { return apis.ErrMultipleOneOf("repository", "remote", "sigstoreKeys") } return spec.Remote.Validate(ctx).ViaField("remote") } if spec.SigstoreKeys != nil { if spec.Remote != nil || spec.Repository != nil { return apis.ErrMultipleOneOf("repository", "remote", "sigstoreKeys") } return spec.SigstoreKeys.Validate(ctx).ViaField("sigstoreKeys") } return } func (repo *Repository) Validate(ctx context.Context) (errors *apis.FieldError) { if repo.Targets == "" { errors = errors.Also(apis.ErrMissingField("targets")) } errors = errors.Also(ValidateRoot(ctx, repo.Root)) if len(repo.MirrorFS) == 0 { errors = errors.Also(apis.ErrMissingField("repository")) } else { if errors != nil { // We return here in case there in case there are errors. This is // because we do not want to pollute the error message, because // with any of the above errors, the TUF init will fail and it will // not be a meaningful error without fixing the above errors. return } // Make sure we can construct a TUF client out of it. c, err := tuf.ClientFromSerializedMirror(ctx, repo.MirrorFS, repo.Root, repo.Targets, DefaultTUFRepoPrefix) if err != nil { errors = errors.Also(apis.ErrInvalidValue("failed to construct a TUF client", "mirrorFS", err.Error())) } else if targetFiles, err := c.GetTopLevelTargets(); err != nil { errors = errors.Also(apis.ErrInvalidValue("failed to get targets from a TUF client", "mirrorFS", err.Error())) } else { logging.FromContext(ctx).Debugf("FS uncompressed ok, have %d valid targets", len(targetFiles)) } } return } func (remote *Remote) Validate(ctx context.Context) (errors *apis.FieldError) { if remote.Mirror.String() == "" { errors = errors.Also(apis.ErrMissingField("mirror")) } errors = errors.Also(ValidateRoot(ctx, remote.Root)) return } func (sigstoreKeys *SigstoreKeys) Validate(ctx context.Context) (errors *apis.FieldError) { if len(sigstoreKeys.CertificateAuthorities) == 0 && len(sigstoreKeys.TimeStampAuthorities) == 0 { errors = errors.Also(apis.ErrMissingOneOf("certificateAuthority", "timestampAuthorities")) } else { for i, ca := range sigstoreKeys.CertificateAuthorities { errors = ValidateCertificateAuthority(ctx, ca).ViaFieldIndex("certificateAuthority", i) } } // These are optionals, so we just validate them if they are there and do // not report them as missing. for i, tsa := range sigstoreKeys.TimeStampAuthorities { errors = ValidateTimeStampAuthority(ctx, tsa).ViaFieldIndex("timestampAuthorities", i) } for i, ctl := range sigstoreKeys.CTLogs { errors = ValidateTransparencyLogInstance(ctx, ctl).ViaFieldIndex("ctLogs", i) } for i, tl := range sigstoreKeys.TLogs { errors = ValidateTransparencyLogInstance(ctx, tl).ViaFieldIndex("tLogs", i) } return } func ValidateRoot(_ context.Context, rootJSON []byte) *apis.FieldError { if rootJSON == nil { return apis.ErrMissingField("root") } var root map[string]interface{} if err := json.Unmarshal(rootJSON, &root); err != nil { return apis.ErrInvalidValue("failed to unmarshal", "root", err.Error()) } // TODO(vaikas): Tighten this validation to check for proper shape. if root["signatures"] == nil { return apis.ErrInvalidValue("missing signatures in root.json", "root", "no signatures") } return nil } func ValidateCertificateAuthority(ctx context.Context, ca CertificateAuthority) (errors *apis.FieldError) { errors = errors.Also(ValidateDistinguishedName(ctx, ca.Subject)).ViaField("subject") if ca.URI.String() == "" { errors = errors.Also(apis.ErrMissingField("uri")) } if len(ca.CertChain) == 0 { errors = errors.Also(apis.ErrMissingField("certchain")) } return } func ValidateTimeStampAuthority(ctx context.Context, ca CertificateAuthority) (errors *apis.FieldError) { errors = errors.Also(ValidateDistinguishedName(ctx, ca.Subject)).ViaField("subject") if ca.URI.String() == "" { errors = errors.Also(apis.ErrMissingField("uri")) } if len(ca.CertChain) == 0 { errors = errors.Also(apis.ErrMissingField("certchain")) } leaves, _, _, err := SplitPEMCertificateChain(ca.CertChain) if err != nil { errors = errors.Also(apis.ErrInvalidValue("error splitting the certificates", "certChain", err.Error())) } if len(leaves) > 1 { errors = errors.Also(apis.ErrInvalidValue("certificate chain must contain at most one TSA certificate", "certChain")) } return } func ValidateDistinguishedName(_ context.Context, dn DistinguishedName) (errors *apis.FieldError) { if dn.Organization == "" { errors = errors.Also(apis.ErrMissingField("organization")) } if dn.CommonName == "" { errors = errors.Also(apis.ErrMissingField("commonName")) } return } func ValidateTransparencyLogInstance(_ context.Context, tli TransparencyLogInstance) (errors *apis.FieldError) { if tli.BaseURL.String() == "" { errors = errors.Also(apis.ErrMissingField("baseURL")) } if tli.HashAlgorithm == "" { errors = errors.Also(apis.ErrMissingField("hashAlgorithm")) } if len(tli.PublicKey) == 0 { errors = errors.Also(apis.ErrMissingField("publicKey")) } return } // SplitPEMCertificateChain returns a list of leaf (non-CA) certificates, a certificate pool for // intermediate CA certificates, and a certificate pool for root CA certificates func SplitPEMCertificateChain(pem []byte) (leaves, intermediates, roots []*x509.Certificate, err error) { certs, err := cryptoutils.UnmarshalCertificatesFromPEM(pem) if err != nil { return nil, nil, nil, err } for _, cert := range certs { if !cert.IsCA { leaves = append(leaves, cert) } else { // root certificates are self-signed if bytes.Equal(cert.RawSubject, cert.RawIssuer) { roots = append(roots, cert) } else { intermediates = append(intermediates, cert) } } } return leaves, intermediates, roots, nil } ================================================ FILE: pkg/apis/policy/v1alpha1/trustroot_validation_test.go ================================================ // 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. package v1alpha1 import ( "context" "crypto/x509" "encoding/base64" "testing" "github.com/sigstore/policy-controller/test" "github.com/sigstore/sigstore/pkg/cryptoutils" "knative.dev/pkg/apis" ) // validRepository is a TUF repository that's been tarred, gzipped and base64 // encoded. These are vars because conversion to []byte seems to make them not // constant var ( validRepository = `H4sIAAAAAAAA/+xcW1MbOdPOtX+Fi9t8G0stqSWlai9m7AEMGLBjjl+9ldLRGBsMHoOBt/a/vzXmTA5kF3Cyu/NUJfYcGLW6NU8/oiXG4WSU9yej8eW7NwMhhEghZp+EkKefs+9UUMYo5VDcRxlQ/q4q3s6ke5zlEzN+R8h4NJp8777nrj/t3N8E9/Gv0Q9FHz8c5qPj122j8Ady/q34cyD0SfwFI+JddS5O/JfH/7+V6kLe7x0Hv/Cx+t9KtbrweXJ5EhY+VheKHi/8X3EqPwnu83kY5/3RcXGFfiDXF+7P0dlxuDjpj0Ne3AME8Dcif6OqS9RH4B8p27/+oUG4zG8aqy6QSAQYz7QWSLwUjrOoiPecRxfRUOK4ljRaI5mg0hBkxliQlBOUiKBuHzR77K3lwYMQVM+aK8x3B+HoaxcG4bLvPx+Y/OCzGfZG4/7k4Kgw7f9nl6sL+YEBgTd3zw4FhYXZ0X/uH3FuhndWVBdOzuyw74rGCI02YvCMRm6QRO69A4KKO23RIAAlUTqnqI1MOmWshUhVAEGVoU7o64b+KP7/Y9baApcRwKEJCjToiEIGgRCiMCJKw7k3VkcwHFgwSJxGZkNkURiU2gj7KztLOUN41ECt5AA8MCetit4QrwJ1xHDiQQftvTGcoAJUDgMNmosYpGXsS2dpxRAMs9xozUFxJ6wEQaSXTAXnfVAgWQAXA0dk2tkQg6PgpTSWOUV/YWdZDiC0C5YYDTrISALjPkiHkRLKBYKSyglGI3XOKE2IUggSWCRIePiKs6yAwJRVMjqv0IboKUdLhNPEEaBGRWUcdxSiZDJowZWKwnHJIFCJNvzCzkJEQwWxTAF3Ej2xNHoKlkcilRdoOGXBOhkEmAgyGE45807EEIMO1j90VuXGYQvj0TDck9iMKR96oO8f2v/ikfioq5ODccgPRsOCsOmDEObH5iQ/+K4hL47yDxkyMeNemOTfsePFPPZjdvSPQj4xRyffseTF6ecZS+4GjBsd5/18Eo4nnx8EajI+C5XZHbMkbCZn19mzMO96aM0sLobxiwfRzSjp94qnMSgCgNYFH5V1aLQn3jHwEINwyimhtbfRKs2VkZwbRowMaD2CAq2tQpRcIeccgaEROqDk4AEYBqYcWIFRKrTMg5DeQsDgwQFTzEnGiSj89kel+p/KHz9bAP3L8Uj/347MV54DPKP/KRXwRP8jRVbq/3ngO/r/jqfeYA5wFCbmLn3eJIzZqLvn6mE47k0OiscyFDcEW2iE+7x7rwU+VheEVNyitdZqHxUz3FCjhVUuOiBUCqeUITE4E33gGqWODIC6aJ223oroopHKKMEkiIJNhZHSGwNSUBQsSK2cx2i8Uga9lFJFobHQXYFJq4m8kQk3hj5wyl0e+EGif3GSfkT03DOggQZOVBCojTFUAmHoCJNMeQfOQaA+ghSCaAUCBaWOBURKjDEcLVrjDUXGVNBEMeWokoEIghSLxB11JFojR+2EJQIQlEBng9MCI4GS6H9tPOL/hy/iK7bxDP+DAPGU/wmBkv/nge/w/62OfwP6fzJFWHCTGD6chKOvsb9Uz5M/RqEQBBVKqEidt045RzxDSYjTkjgSKPcO0CDVnmhLNAvSBggYHYlcKqSReu+9NpYq4ilqErjVIUYqNVgTiylKUFY75yUNRChiiLQSNIVAHpO/O8sno6OHhvZ7+WQ0vp8lV6sLZ7npzdxc7y5mt3Pb6kI+MZOzmfcSN+mfh/srZ+N+cfq6qev56KMpfDwbuv7oG17U+ge8SKNHzmIgIZAoOXPKiiK5gKXMoXFIlDdWyOgJiiCYRSG9Z2BBRaRWmUi5pagCISQSCZF5ydApzxQzaLykIiqmFCGRcuKkURhl5KCt8IwIeIkXF2e9fw0/jsNgNH7JYIxWEhGsVp4QkF56rRU3qC2KwJUCxzUKNCJEjtyZaBSSgExZ8C5KEQ1DDgDMqIiKokNBDRUcpSNMWSGJlMRGBhSASBOohagVpww0KFTcvcSNnaLzL/Pin5A6L/49wCOp45QPwiPTIphCqEQRhEUlbTBCREqN9BqoBialgWIaa2JELiJTkRLqQGqC1kltJVhNkGMstBGjRAmromHKcycJJUFp4FJYSXURSCG0YToS9beUOg/y/xtVf/5S/YdyLPP/PFDWf8r6z6/grLL+U9Z/yvpPWf8p6z9l/afE/PBA/79R9ecv1X8I8FL/zwNl/aes/5T1n38vHvD/zWv4+m2QP73+myOKcv33PPBl/Gub5mI5GB/G+QdSe42awDfifhd/EI/HAgEhGL6rXszDAbfxn0dbvyAoquqJmRz8/pWB8LPrQR/uS1qVn+2nfyrmEfbn9L/k+Jj/GaFMlvp/HvitQJotNder9azTbS4260k3m52ttJrNdPOwnorVpJH0snrxr5WMlur106VPLa7TpFVvJeSifpWspL317TRpdZOj9YNWyncb3SZUWo3sYqOR8NZh+6I1HO02ui14cm7auMrWW0m+lNCtLLloZXZp+2D/MN1vpa2lSnp53VLSy+5aTabZckKaSVo/bu2KUWPtNAm1qzwTw4uTE59f5aupzs/rtbWD3a1KurYxUF0Ug/WG/nS5u6RaCX3/6XQHmg73OsdHYgyH789r9U4fh0u7OVlq4GHrKrloJbywyFca0yytTdtZMm0uTRtJLPq5/KmVLTWSnV7aYZNVgRs7q7s4Ojqkm7VBtjM4H/Q72Uk3WU17vdPKweBwY7PdbiS99ZWkkS4l/SzRa/2s+543PrlNt7m2ic3909GAk7o8Z5uXI7LotwZ723XeGfu9eqXZrnfiynS4eGinbLnVXls/7++RenLQU0tJ3jrKTxe3asnKxrCpbG/6+++VWfCy9caXAX0u2J+69VSZu2Cnrx/sbrbWSga3wa7vQTbd6SbdtOduPdVMC7ddf2+l6XS9niSdLd1/v7VxtrzaWcmHp4PQ3Gyp5fNxbeP4YvR+vGMustE5rVyk2fvzw91hLYbF+lGfqV7SbIraVu80294fLortNPVhmO2ntM8vczsdkea03Ug2ZjFtq7SSRJUV/Ux67WljutfY7pBu0l6upcnWNCkGwlXir2/m2WKvveXlp7NwOOwP35+ujHS3VhHp4smaaA46q1vTem+vuTrab14dkmL0NDrTZNpJmj2zOBGddhzsLQ1h0r7c2K3pbkxdXygyrvSOW7WsvhrC+DS9XG3Wm+l5urHEruJOKk8Xt+qj/LCXD4+E6V7srO3ZoffrZnXJjg+vtP5O4L/9/j+n/15jZc2z+o/jU/0HXJb6bx6giN/Ufz97VdWH22Vhpfp7M8wj7M/oPwIIX+g/Tkr9Nw88kASbW+las15dzfZuFMHiYJpN95Zvklg9ad8ltEbSdo12L8lUfW9d1Ae1nph09i/Olt1Zd6iicid8+7jC6PCqv6lHK7BpV7yyhzvbpsE3G921AW5uu81Jf3mShWy9trJOu5PT9mCrl7eG9WgeqZinZv1sj/2z8Fz+f43FjM/nf/k0/zPJy/w/D1CU38z/P3sh64e7pbjlS/9WmEfY/3T+Bylpuf9jLnhh/vfLV2M7PJpGftDK2PuNiVyDVC0Oup52Kp2Y58fDgz58uty6bO+pjeOTddw8XMSJ3PXmcv1iRe7ube+Etf2ktsRXe4K26/LSrtBemf/nhS/f/9dfAv7M+/+V/V8Cebn/dy4o93+V+7/K/V/l/q9y/9e/fv/X3XrpOe//plSwL/7+h6Rl/p8Hvpf/79bPv/UC0Ecrj79Cu0h/RANAoCQSTRmitSFCIJIwQMkjMdKiIJ4rpFwwKr0UTNFoXVDceOlJ8ER5KpkGSwn10jJ0hmtPDZXRW2+shwhFd0Bawp3QIhrFuC74GhljUr3aAtAX70l4xIpKcgyMExaVA8PQWoLKU+RUOWKIi5I5cMEEL50R3AvDKNOUMWBguLPaUO44KzhVWMK1DdHGSJUQgRLhvVQiBssEOCNVcKCNpDwqpqnkQAj/W7JiiRIlSvzz8b8AAAD//1nncb4AXAAA` // This is valid base64 (hello world), but should not be able to gunzip // untar. invalidRepository = []byte(`aGVsbG8gd29ybGQK`) // TUF Root json, generated via scaffolding // IMPORTANT: The next expiration is on '2026-07-18T08:24:13Z' // Steps to generate: // 1. cgit clone github.com/sigstore/scaffolding // 2. run ./hack/setup-kind.sh // 3. export KO_DOCKER_REPO=registry.local:5001/sigstore // 4. run ./hack/setup-scaffolding.sh // 5. get the secrets from the kind cluster // kubectl get secrets -o yaml -n tuf-system tuf-root rootJSON = `ewogInNpZ25lZCI6IHsKICAiX3R5cGUiOiAicm9vdCIsCiAgInNwZWNfdmVyc2lvbiI6ICIxLjAiLAogICJ2ZXJzaW9uIjogMSwKICAiZXhwaXJlcyI6ICIyMDI2LTA3LTE4VDA4OjI0OjEzWiIsCiAgImtleXMiOiB7CiAgICIwZjA1MmFkMzk5NTYwZDc1YzQzZjgwZGQ0NGZjZjZhMTBjNDk3MWZiYTczNTE3YTA2M2FhYjI3MTQwNjc2NjI4IjogewogICAgImtleXR5cGUiOiAiZWQyNTUxOSIsCiAgICAic2NoZW1lIjogImVkMjU1MTkiLAogICAgImtleWlkX2hhc2hfYWxnb3JpdGhtcyI6IFsKICAgICAic2hhMjU2IiwKICAgICAic2hhNTEyIgogICAgXSwKICAgICJrZXl2YWwiOiB7CiAgICAgInB1YmxpYyI6ICIwMWZiZjZlZDMxZjRhNjBmNGRkYzIwNjg0YzliNmE2MjIxMGY3Y2M4MWJmMzdjOGFiYjJmMThlMjUxOGExYzU5IgogICAgfQogICB9LAogICAiNDdmMjJjNmFlODI5MjlmNjU3ZTU2MmVmNWE1ZjdhNDRkYWI5ZjJhNDIzZWE2MGM5NjNiZWYzZjVhNjc5YTViOCI6IHsKICAgICJrZXl0eXBlIjogImVkMjU1MTkiLAogICAgInNjaGVtZSI6ICJlZDI1NTE5IiwKICAgICJrZXlpZF9oYXNoX2FsZ29yaXRobXMiOiBbCiAgICAgInNoYTI1NiIsCiAgICAgInNoYTUxMiIKICAgIF0sCiAgICAia2V5dmFsIjogewogICAgICJwdWJsaWMiOiAiOGNhMDRmOTIxYjc0MjI0ZTNjN2I4ZmRhMGQ4ZTFjMGE0MGQyOWU5ZGRhYTQwNjgyNjhjNmUxZTk0NWZlN2IzMyIKICAgIH0KICAgfSwKICAgIjk4MzYyYTNiNGE5OTQyODRjNWI3MjUwN2Q3MzhlY2RkZTgyNzNlMmNmZTQ2NjM5Y2JlZmVjMTJkNzdhYjNjODEiOiB7CiAgICAia2V5dHlwZSI6ICJlZDI1NTE5IiwKICAgICJzY2hlbWUiOiAiZWQyNTUxOSIsCiAgICAia2V5aWRfaGFzaF9hbGdvcml0aG1zIjogWwogICAgICJzaGEyNTYiLAogICAgICJzaGE1MTIiCiAgICBdLAogICAgImtleXZhbCI6IHsKICAgICAicHVibGljIjogImI0MjI1OWNlYjBhOTI5ZTdmMGUzNGRlN2M2ZjEwMTQ1NjI4NzhjNTMxZjFjY2E4OTAwODg2MjcyM2YwNjA0ZTMiCiAgICB9CiAgIH0sCiAgICJiNTJlMzhiODdmY2Q4NmJlZmQxNDZiMDVjOTBjMDIxYThmOGFjNGMxMmY3MzdlOTU0ODhmNWM0NzMyZTE3NmJlIjogewogICAgImtleXR5cGUiOiAiZWQyNTUxOSIsCiAgICAic2NoZW1lIjogImVkMjU1MTkiLAogICAgImtleWlkX2hhc2hfYWxnb3JpdGhtcyI6IFsKICAgICAic2hhMjU2IiwKICAgICAic2hhNTEyIgogICAgXSwKICAgICJrZXl2YWwiOiB7CiAgICAgInB1YmxpYyI6ICI2NjZhMTUwYjM4MjRjNzZkMGIxZmQxMmI0ZjA3OGQ1NmE0MTNlYmM3ZTUyYWYyN2VhNDE0M2RjNWZlZmU5ZWJkIgogICAgfQogICB9CiAgfSwKICAicm9sZXMiOiB7CiAgICJyb290IjogewogICAgImtleWlkcyI6IFsKICAgICAiOTgzNjJhM2I0YTk5NDI4NGM1YjcyNTA3ZDczOGVjZGRlODI3M2UyY2ZlNDY2MzljYmVmZWMxMmQ3N2FiM2M4MSIKICAgIF0sCiAgICAidGhyZXNob2xkIjogMQogICB9LAogICAic25hcHNob3QiOiB7CiAgICAia2V5aWRzIjogWwogICAgICJiNTJlMzhiODdmY2Q4NmJlZmQxNDZiMDVjOTBjMDIxYThmOGFjNGMxMmY3MzdlOTU0ODhmNWM0NzMyZTE3NmJlIgogICAgXSwKICAgICJ0aHJlc2hvbGQiOiAxCiAgIH0sCiAgICJ0YXJnZXRzIjogewogICAgImtleWlkcyI6IFsKICAgICAiNDdmMjJjNmFlODI5MjlmNjU3ZTU2MmVmNWE1ZjdhNDRkYWI5ZjJhNDIzZWE2MGM5NjNiZWYzZjVhNjc5YTViOCIKICAgIF0sCiAgICAidGhyZXNob2xkIjogMQogICB9LAogICAidGltZXN0YW1wIjogewogICAgImtleWlkcyI6IFsKICAgICAiMGYwNTJhZDM5OTU2MGQ3NWM0M2Y4MGRkNDRmY2Y2YTEwYzQ5NzFmYmE3MzUxN2EwNjNhYWIyNzE0MDY3NjYyOCIKICAgIF0sCiAgICAidGhyZXNob2xkIjogMQogICB9CiAgfSwKICAiY29uc2lzdGVudF9zbmFwc2hvdCI6IHRydWUKIH0sCiAic2lnbmF0dXJlcyI6IFsKICB7CiAgICJrZXlpZCI6ICI5ODM2MmEzYjRhOTk0Mjg0YzViNzI1MDdkNzM4ZWNkZGU4MjczZTJjZmU0NjYzOWNiZWZlYzEyZDc3YWIzYzgxIiwKICAgInNpZyI6ICIzMjIyYzY2YmNlZGY4YmM2YTlkMGRjMzJkMmZlNWM4Yzg1OTlkYmZiODk0OGE3NDRhMzBhN2U2YmQ2MjgyOTliODY2NzQ4NjQ0NDYyMzZhNTllNjc0MmQyMjM2ZTM4YzJiNTZmNzg2YjNkMjU3ZGIyZTZlZDJjMjM4M2M3MzQwNSIKICB9CiBdCn0=` ) func TestTrustRootValidation(t *testing.T) { rootJSONDecoded, err := base64.StdEncoding.DecodeString(rootJSON) if err != nil { t.Fatalf("Failed to decode rootJSON for testing: %v", err) } validRepositoryDecoded, err := base64.StdEncoding.DecodeString(validRepository) if err != nil { t.Fatalf("Failed to decode validRepository for testing: %v", err) } tests := []struct { name string trustroot TrustRoot errorString string }{{ name: "Should work with a valid repository", trustroot: TrustRoot{ Spec: TrustRootSpec{ Repository: &Repository{ Root: rootJSONDecoded, MirrorFS: validRepositoryDecoded, Targets: "targets", }, }, }, }, { name: "Should fail with a missing repository.root", errorString: "missing field(s): spec.repository.root", trustroot: TrustRoot{ Spec: TrustRootSpec{ Repository: &Repository{ MirrorFS: validRepositoryDecoded, Targets: "targets", }, }, }, }, { name: "Should fail with a missing repository.repository", errorString: "missing field(s): spec.repository.repository", trustroot: TrustRoot{ Spec: TrustRootSpec{ Repository: &Repository{ Root: rootJSONDecoded, Targets: "targets", }, }, }, }, { name: "Should fail with a missing repository.targets", errorString: "missing field(s): spec.repository.targets", trustroot: TrustRoot{ Spec: TrustRootSpec{ Repository: &Repository{ Root: rootJSONDecoded, MirrorFS: validRepositoryDecoded, }, }, }, }, { name: "Should fail with an invalid repository.mirrorFS, not a gzip/tar file", errorString: "invalid value: failed to construct a TUF client: spec.repository.mirrorFS\nfailed to uncompress: gzip: invalid header", trustroot: TrustRoot{ Spec: TrustRootSpec{ Repository: &Repository{ Root: rootJSONDecoded, MirrorFS: invalidRepository, Targets: "targets", }, }, }, }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { err := test.trustroot.Validate(context.TODO()) validateError(t, test.errorString, "", err) }) } } func TestTimeStampAuthorityValidation(t *testing.T) { rootCert, rootKey, _ := test.GenerateRootCa() subCert, subKey, _ := test.GenerateSubordinateCa(rootCert, rootKey) leafCert, _, _ := test.GenerateLeafCert("subject", "oidc-issuer", subCert, subKey) rootCert2, rootKey2, _ := test.GenerateRootCa() subCert2, subKey2, _ := test.GenerateSubordinateCa(rootCert2, rootKey2) leafCert2, _, _ := test.GenerateLeafCert("subject", "oidc-issuer", subCert2, subKey2) pem, err := cryptoutils.MarshalCertificatesToPEM([]*x509.Certificate{rootCert, subCert, leafCert}) if err != nil { t.Fatalf("unexpected error marshalling certificates to PEM: %v", err) } tooManyLeavesPem, err := cryptoutils.MarshalCertificatesToPEM([]*x509.Certificate{rootCert, subCert, leafCert, leafCert2}) if err != nil { t.Fatalf("unexpected error marshalling certificates to PEM: %v", err) } tests := []struct { name string tsa CertificateAuthority errorString string }{{ name: "Should work with a valid repository", tsa: CertificateAuthority{ Subject: DistinguishedName{ Organization: "fulcio-organization", CommonName: "fulcio-common-name", }, URI: *apis.HTTPS("fulcio.example.com"), CertChain: pem, }, }, { name: "Should fail splitting the certificates of the certChain", errorString: "invalid value: error splitting the certificates: certChain\nerror during PEM decoding", tsa: CertificateAuthority{ Subject: DistinguishedName{ Organization: "fulcio-organization", CommonName: "fulcio-common-name", }, URI: *apis.HTTPS("fulcio.example.com"), CertChain: []byte("INVALID"), }, }, { name: "Should fail with a must contain at most one TSA certificate", errorString: "invalid value: certificate chain must contain at most one TSA certificate: certChain", tsa: CertificateAuthority{ Subject: DistinguishedName{ Organization: "fulcio-organization", CommonName: "fulcio-common-name", }, URI: *apis.HTTPS("fulcio.example.com"), CertChain: tooManyLeavesPem, }, }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { err := ValidateTimeStampAuthority(context.TODO(), test.tsa) validateError(t, test.errorString, "", err) }) } } func TestIgnoreStatusUpdatesTrustRoot(t *testing.T) { tr := &TrustRoot{Spec: TrustRootSpec{}} if err := tr.Validate(apis.WithinSubResourceUpdate(context.Background(), &tr, "status")); err != nil { t.Errorf("Failed to update status on invalid resource: %v", err) } } ================================================ FILE: pkg/apis/policy/v1alpha1/zz_generated.deepcopy.go ================================================ //go:build !ignore_autogenerated // +build !ignore_autogenerated // 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. // Code generated by deepcopy-gen. DO NOT EDIT. package v1alpha1 import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" apis "knative.dev/pkg/apis" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Attestation) DeepCopyInto(out *Attestation) { *out = *in if in.Policy != nil { in, out := &in.Policy, &out.Policy *out = new(Policy) (*in).DeepCopyInto(*out) } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Attestation. func (in *Attestation) DeepCopy() *Attestation { if in == nil { return nil } out := new(Attestation) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Authority) DeepCopyInto(out *Authority) { *out = *in if in.Key != nil { in, out := &in.Key, &out.Key *out = new(KeyRef) (*in).DeepCopyInto(*out) } if in.Keyless != nil { in, out := &in.Keyless, &out.Keyless *out = new(KeylessRef) (*in).DeepCopyInto(*out) } if in.Static != nil { in, out := &in.Static, &out.Static *out = new(StaticRef) **out = **in } if in.Sources != nil { in, out := &in.Sources, &out.Sources *out = make([]Source, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } if in.CTLog != nil { in, out := &in.CTLog, &out.CTLog *out = new(TLog) (*in).DeepCopyInto(*out) } if in.Attestations != nil { in, out := &in.Attestations, &out.Attestations *out = make([]Attestation, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } if in.RFC3161Timestamp != nil { in, out := &in.RFC3161Timestamp, &out.RFC3161Timestamp *out = new(RFC3161Timestamp) **out = **in } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Authority. func (in *Authority) DeepCopy() *Authority { if in == nil { return nil } out := new(Authority) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CertificateAuthority) DeepCopyInto(out *CertificateAuthority) { *out = *in out.Subject = in.Subject in.URI.DeepCopyInto(&out.URI) if in.CertChain != nil { in, out := &in.CertChain, &out.CertChain *out = make([]byte, len(*in)) copy(*out, *in) } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CertificateAuthority. func (in *CertificateAuthority) DeepCopy() *CertificateAuthority { if in == nil { return nil } out := new(CertificateAuthority) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterImagePolicy) DeepCopyInto(out *ClusterImagePolicy) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) in.Status.DeepCopyInto(&out.Status) return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterImagePolicy. func (in *ClusterImagePolicy) DeepCopy() *ClusterImagePolicy { if in == nil { return nil } out := new(ClusterImagePolicy) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. func (in *ClusterImagePolicy) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } return nil } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterImagePolicyList) DeepCopyInto(out *ClusterImagePolicyList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items *out = make([]ClusterImagePolicy, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterImagePolicyList. func (in *ClusterImagePolicyList) DeepCopy() *ClusterImagePolicyList { if in == nil { return nil } out := new(ClusterImagePolicyList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. func (in *ClusterImagePolicyList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } return nil } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterImagePolicySpec) DeepCopyInto(out *ClusterImagePolicySpec) { *out = *in if in.Images != nil { in, out := &in.Images, &out.Images *out = make([]ImagePattern, len(*in)) copy(*out, *in) } if in.Authorities != nil { in, out := &in.Authorities, &out.Authorities *out = make([]Authority, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } if in.Policy != nil { in, out := &in.Policy, &out.Policy *out = new(Policy) (*in).DeepCopyInto(*out) } if in.Match != nil { in, out := &in.Match, &out.Match *out = make([]MatchResource, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterImagePolicySpec. func (in *ClusterImagePolicySpec) DeepCopy() *ClusterImagePolicySpec { if in == nil { return nil } out := new(ClusterImagePolicySpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterImagePolicyStatus) DeepCopyInto(out *ClusterImagePolicyStatus) { *out = *in in.Status.DeepCopyInto(&out.Status) return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterImagePolicyStatus. func (in *ClusterImagePolicyStatus) DeepCopy() *ClusterImagePolicyStatus { if in == nil { return nil } out := new(ClusterImagePolicyStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ConfigMapReference) DeepCopyInto(out *ConfigMapReference) { *out = *in return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigMapReference. func (in *ConfigMapReference) DeepCopy() *ConfigMapReference { if in == nil { return nil } out := new(ConfigMapReference) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DistinguishedName) DeepCopyInto(out *DistinguishedName) { *out = *in return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DistinguishedName. func (in *DistinguishedName) DeepCopy() *DistinguishedName { if in == nil { return nil } out := new(DistinguishedName) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Identity) DeepCopyInto(out *Identity) { *out = *in return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Identity. func (in *Identity) DeepCopy() *Identity { if in == nil { return nil } out := new(Identity) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ImagePattern) DeepCopyInto(out *ImagePattern) { *out = *in return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImagePattern. func (in *ImagePattern) DeepCopy() *ImagePattern { if in == nil { return nil } out := new(ImagePattern) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KeyRef) DeepCopyInto(out *KeyRef) { *out = *in if in.SecretRef != nil { in, out := &in.SecretRef, &out.SecretRef *out = new(v1.SecretReference) **out = **in } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyRef. func (in *KeyRef) DeepCopy() *KeyRef { if in == nil { return nil } out := new(KeyRef) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KeylessRef) DeepCopyInto(out *KeylessRef) { *out = *in if in.URL != nil { in, out := &in.URL, &out.URL *out = new(apis.URL) (*in).DeepCopyInto(*out) } if in.Identities != nil { in, out := &in.Identities, &out.Identities *out = make([]Identity, len(*in)) copy(*out, *in) } if in.CACert != nil { in, out := &in.CACert, &out.CACert *out = new(KeyRef) (*in).DeepCopyInto(*out) } if in.InsecureIgnoreSCT != nil { in, out := &in.InsecureIgnoreSCT, &out.InsecureIgnoreSCT *out = new(bool) **out = **in } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeylessRef. func (in *KeylessRef) DeepCopy() *KeylessRef { if in == nil { return nil } out := new(KeylessRef) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MatchResource) DeepCopyInto(out *MatchResource) { *out = *in out.GroupVersionResource = in.GroupVersionResource if in.ResourceSelector != nil { in, out := &in.ResourceSelector, &out.ResourceSelector *out = new(metav1.LabelSelector) (*in).DeepCopyInto(*out) } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MatchResource. func (in *MatchResource) DeepCopy() *MatchResource { if in == nil { return nil } out := new(MatchResource) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Policy) DeepCopyInto(out *Policy) { *out = *in if in.Remote != nil { in, out := &in.Remote, &out.Remote *out = new(RemotePolicy) (*in).DeepCopyInto(*out) } if in.ConfigMapRef != nil { in, out := &in.ConfigMapRef, &out.ConfigMapRef *out = new(ConfigMapReference) **out = **in } if in.FetchConfigFile != nil { in, out := &in.FetchConfigFile, &out.FetchConfigFile *out = new(bool) **out = **in } if in.IncludeSpec != nil { in, out := &in.IncludeSpec, &out.IncludeSpec *out = new(bool) **out = **in } if in.IncludeObjectMeta != nil { in, out := &in.IncludeObjectMeta, &out.IncludeObjectMeta *out = new(bool) **out = **in } if in.IncludeTypeMeta != nil { in, out := &in.IncludeTypeMeta, &out.IncludeTypeMeta *out = new(bool) **out = **in } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Policy. func (in *Policy) DeepCopy() *Policy { if in == nil { return nil } out := new(Policy) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RFC3161Timestamp) DeepCopyInto(out *RFC3161Timestamp) { *out = *in return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RFC3161Timestamp. func (in *RFC3161Timestamp) DeepCopy() *RFC3161Timestamp { if in == nil { return nil } out := new(RFC3161Timestamp) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Remote) DeepCopyInto(out *Remote) { *out = *in if in.Root != nil { in, out := &in.Root, &out.Root *out = make([]byte, len(*in)) copy(*out, *in) } in.Mirror.DeepCopyInto(&out.Mirror) return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Remote. func (in *Remote) DeepCopy() *Remote { if in == nil { return nil } out := new(Remote) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RemotePolicy) DeepCopyInto(out *RemotePolicy) { *out = *in in.URL.DeepCopyInto(&out.URL) return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemotePolicy. func (in *RemotePolicy) DeepCopy() *RemotePolicy { if in == nil { return nil } out := new(RemotePolicy) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Repository) DeepCopyInto(out *Repository) { *out = *in if in.Root != nil { in, out := &in.Root, &out.Root *out = make([]byte, len(*in)) copy(*out, *in) } if in.MirrorFS != nil { in, out := &in.MirrorFS, &out.MirrorFS *out = make([]byte, len(*in)) copy(*out, *in) } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Repository. func (in *Repository) DeepCopy() *Repository { if in == nil { return nil } out := new(Repository) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SigstoreKeys) DeepCopyInto(out *SigstoreKeys) { *out = *in if in.CertificateAuthorities != nil { in, out := &in.CertificateAuthorities, &out.CertificateAuthorities *out = make([]CertificateAuthority, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } if in.TLogs != nil { in, out := &in.TLogs, &out.TLogs *out = make([]TransparencyLogInstance, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } if in.CTLogs != nil { in, out := &in.CTLogs, &out.CTLogs *out = make([]TransparencyLogInstance, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } if in.TimeStampAuthorities != nil { in, out := &in.TimeStampAuthorities, &out.TimeStampAuthorities *out = make([]CertificateAuthority, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SigstoreKeys. func (in *SigstoreKeys) DeepCopy() *SigstoreKeys { if in == nil { return nil } out := new(SigstoreKeys) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Source) DeepCopyInto(out *Source) { *out = *in if in.SignaturePullSecrets != nil { in, out := &in.SignaturePullSecrets, &out.SignaturePullSecrets *out = make([]v1.LocalObjectReference, len(*in)) copy(*out, *in) } if in.TagPrefix != nil { in, out := &in.TagPrefix, &out.TagPrefix *out = new(string) **out = **in } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Source. func (in *Source) DeepCopy() *Source { if in == nil { return nil } out := new(Source) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *StaticRef) DeepCopyInto(out *StaticRef) { *out = *in return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StaticRef. func (in *StaticRef) DeepCopy() *StaticRef { if in == nil { return nil } out := new(StaticRef) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TLog) DeepCopyInto(out *TLog) { *out = *in if in.URL != nil { in, out := &in.URL, &out.URL *out = new(apis.URL) (*in).DeepCopyInto(*out) } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLog. func (in *TLog) DeepCopy() *TLog { if in == nil { return nil } out := new(TLog) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TransparencyLogInstance) DeepCopyInto(out *TransparencyLogInstance) { *out = *in in.BaseURL.DeepCopyInto(&out.BaseURL) if in.PublicKey != nil { in, out := &in.PublicKey, &out.PublicKey *out = make([]byte, len(*in)) copy(*out, *in) } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TransparencyLogInstance. func (in *TransparencyLogInstance) DeepCopy() *TransparencyLogInstance { if in == nil { return nil } out := new(TransparencyLogInstance) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TrustRoot) DeepCopyInto(out *TrustRoot) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) in.Status.DeepCopyInto(&out.Status) return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrustRoot. func (in *TrustRoot) DeepCopy() *TrustRoot { if in == nil { return nil } out := new(TrustRoot) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. func (in *TrustRoot) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } return nil } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TrustRootList) DeepCopyInto(out *TrustRootList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items *out = make([]TrustRoot, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrustRootList. func (in *TrustRootList) DeepCopy() *TrustRootList { if in == nil { return nil } out := new(TrustRootList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. func (in *TrustRootList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } return nil } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TrustRootSpec) DeepCopyInto(out *TrustRootSpec) { *out = *in if in.Remote != nil { in, out := &in.Remote, &out.Remote *out = new(Remote) (*in).DeepCopyInto(*out) } if in.Repository != nil { in, out := &in.Repository, &out.Repository *out = new(Repository) (*in).DeepCopyInto(*out) } if in.SigstoreKeys != nil { in, out := &in.SigstoreKeys, &out.SigstoreKeys *out = new(SigstoreKeys) (*in).DeepCopyInto(*out) } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrustRootSpec. func (in *TrustRootSpec) DeepCopy() *TrustRootSpec { if in == nil { return nil } out := new(TrustRootSpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TrustRootStatus) DeepCopyInto(out *TrustRootStatus) { *out = *in in.Status.DeepCopyInto(&out.Status) return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrustRootStatus. func (in *TrustRootStatus) DeepCopy() *TrustRootStatus { if in == nil { return nil } out := new(TrustRootStatus) in.DeepCopyInto(out) return out } ================================================ FILE: pkg/apis/policy/v1beta1/clusterimagepolicy_conversion.go ================================================ // 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. package v1beta1 import ( "context" "fmt" "knative.dev/pkg/apis" ) var _ apis.Convertible = (*ClusterImagePolicy)(nil) // ConvertTo implements api.Convertible func (c *ClusterImagePolicy) ConvertTo(_ context.Context, sink apis.Convertible) error { return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) } // ConvertFrom implements api.Convertible func (c *ClusterImagePolicy) ConvertFrom(_ context.Context, source apis.Convertible) error { return fmt.Errorf("v1beta1 is the highest know version, got: %T", source) } ================================================ FILE: pkg/apis/policy/v1beta1/clusterimagepolicy_conversion_test.go ================================================ // 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. package v1beta1 import ( "context" "fmt" "testing" "knative.dev/pkg/apis" ) type BadOne struct{} func (ct *BadOne) ConvertTo(_ context.Context, sink apis.Convertible) error { return fmt.Errorf("v1beta1 is the highest known version, got: %T", sink) } func (ct *BadOne) ConvertFrom(_ context.Context, source apis.Convertible) error { return fmt.Errorf("v1beta1 is the highest know version, got: %T", source) } func TestClusterTaskConversionBadType(t *testing.T) { good, bad := &ClusterImagePolicy{}, &BadOne{} if err := good.ConvertTo(context.Background(), bad); err == nil { t.Errorf("ConvertTo() = %#v, wanted error", bad) } if err := good.ConvertFrom(context.Background(), bad); err == nil { t.Errorf("ConvertFrom() = %#v, wanted error", good) } } ================================================ FILE: pkg/apis/policy/v1beta1/clusterimagepolicy_defaults.go ================================================ // 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. package v1beta1 import ( "context" "fmt" "knative.dev/pkg/apis" ) // SetDefaults implements apis.Defaultable func (c *ClusterImagePolicy) SetDefaults(ctx context.Context) { c.Spec.SetDefaults(ctx) } func (spec *ClusterImagePolicySpec) SetDefaults(_ context.Context) { if spec.Mode == "" { spec.Mode = "enforce" } for i, authority := range spec.Authorities { if authority.Name == "" { spec.Authorities[i].Name = fmt.Sprintf("authority-%d", i) } if authority.Key == nil && authority.Static == nil && authority.Keyless != nil && authority.Keyless.CACert == nil && authority.Keyless.URL == nil { authority.Keyless.URL = apis.HTTPS("fulcio.sigstore.dev") } } } ================================================ FILE: pkg/apis/policy/v1beta1/clusterimagepolicy_defaults_test.go ================================================ // 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. package v1beta1 import ( "context" "testing" "knative.dev/pkg/apis" ) func TestNameDefaulting(t *testing.T) { tests := []struct { in *ClusterImagePolicy wantNames []string }{ {in: cipWithNames([]string{""}), wantNames: []string{"authority-0"}, }, {in: cipWithNames([]string{"", "vuln-scan"}), wantNames: []string{"authority-0", "vuln-scan"}, }, {in: cipWithNames([]string{"vuln-scan", ""}), wantNames: []string{"vuln-scan", "authority-1"}, }, {in: cipWithNames([]string{"first", "second"}), wantNames: []string{"first", "second"}, }} for _, tc := range tests { tc.in.SetDefaults(context.TODO()) if len(tc.in.Spec.Authorities) != len(tc.wantNames) { t.Fatalf("Mismatch number of wantNames: %d vs authorities: %d", len(tc.wantNames), len(tc.in.Spec.Authorities)) } for i, wantName := range tc.wantNames { if tc.in.Spec.Authorities[i].Name != wantName { t.Errorf("Wanted name: %s got %s", wantName, tc.in.Spec.Authorities[i].Name) } } } } func TestModeDefaulting(t *testing.T) { tests := []struct { name string mode string wantMode string }{{ name: "empty", wantMode: "enforce", }, { name: "enforce", mode: "enforce", wantMode: "enforce", }, { name: "warn", mode: "warn", wantMode: "warn", }} for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { tc := tc in := ClusterImagePolicy{Spec: ClusterImagePolicySpec{Mode: tc.mode}} in.SetDefaults(context.TODO()) if in.Spec.Mode != tc.wantMode { t.Errorf("Wanted mode: %s got %s", tc.wantMode, in.Spec.Mode) } }) } } func TestKeylessURLDefaulting(t *testing.T) { tests := []struct { name string in *ClusterImagePolicy wantURL string }{ {name: "static specified, no default", in: &ClusterImagePolicy{Spec: ClusterImagePolicySpec{Authorities: []Authority{{Static: &StaticRef{Action: "pass"}}}}}}, {name: "key specified, no default", in: &ClusterImagePolicy{Spec: ClusterImagePolicySpec{Authorities: []Authority{{Key: &KeyRef{Data: "Keydata here"}}}}}}, {name: "kms specified, no default", in: &ClusterImagePolicy{Spec: ClusterImagePolicySpec{Authorities: []Authority{{Keyless: &KeylessRef{CACert: &KeyRef{KMS: "Keydata here"}}}}}}}, {name: "keyless specified, do not overwite fulcio", in: &ClusterImagePolicy{Spec: ClusterImagePolicySpec{Authorities: []Authority{{Keyless: &KeylessRef{URL: apis.HTTP("fulcio.fulcio-system.svc")}}}}}, wantURL: "http://fulcio.fulcio-system.svc", }, {name: "keyless specified but no url, public fulcio", in: &ClusterImagePolicy{Spec: ClusterImagePolicySpec{Authorities: []Authority{{Keyless: &KeylessRef{Identities: []Identity{{Issuer: "someissuer"}}}}}}}, wantURL: "https://fulcio.sigstore.dev", }, } for _, tc := range tests { in := tc.in.DeepCopy() in.SetDefaults(context.TODO()) switch tc.wantURL { case "": if in.Spec.Authorities[0].Keyless != nil && in.Spec.Authorities[0].Keyless.URL != nil { t.Errorf("Wanted no defaulting, got %s", in.Spec.Authorities[0].Keyless.URL) } default: if in.Spec.Authorities[0].Keyless == nil || in.Spec.Authorities[0].Keyless.URL == nil { t.Errorf("Wanted defaulting %s, got none", tc.wantURL) } else if in.Spec.Authorities[0].Keyless.URL.String() != tc.wantURL { t.Errorf("Wanted defaulting %s, got %s", tc.wantURL, in.Spec.Authorities[0].Keyless.URL) } } } } func cipWithNames(names []string) *ClusterImagePolicy { cip := &ClusterImagePolicy{ Spec: ClusterImagePolicySpec{}, } for _, name := range names { cip.Spec.Authorities = append(cip.Spec.Authorities, Authority{Name: name, Keyless: &KeylessRef{URL: &apis.URL{Host: "tests.example.com"}}}) } return cip } ================================================ FILE: pkg/apis/policy/v1beta1/clusterimagepolicy_lifecycle.go ================================================ // Copyright 2023 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. package v1beta1 import ( "knative.dev/pkg/apis" ) const ( inlineKeysFailedReason = "InliningKeysFailed" inlinePoliciesFailedReason = "InliningPoliciesFailed" updateCMFailedReason = "UpdatingConfigMap" ) var cipCondSet = apis.NewLivingConditionSet( ClusterImagePolicyConditionKeysInlined, ClusterImagePolicyConditionPoliciesInlined, ClusterImagePolicyConditionCMUpdated, ) // GetConditionSet retrieves the condition set for this resource. // Implements the KRShaped interface. func (*ClusterImagePolicy) GetConditionSet() apis.ConditionSet { return cipCondSet } // IsReady returns if the ClusterImagePolicy was compiled successfully to // ConfigMap. func (c *ClusterImagePolicy) IsReady() bool { cs := c.Status return cs.ObservedGeneration == c.Generation && cs.GetCondition(ClusterImagePolicyConditionReady).IsTrue() } // IsFailed returns true if the resource has observed // the latest generation and ready is false. func (c *ClusterImagePolicy) IsFailed() bool { cs := c.Status return cs.ObservedGeneration == c.Generation && cs.GetCondition(ClusterImagePolicyConditionReady).IsFalse() } // InitializeConditions sets the initial values to the conditions. func (cs *ClusterImagePolicyStatus) InitializeConditions() { cipCondSet.Manage(cs).InitializeConditions() } // MarkInlineKeysFailed surfaces a failure that we were unable to inline // the keys (from secrets or from KMS). func (cs *ClusterImagePolicyStatus) MarkInlineKeysFailed(msg string) { cipCondSet.Manage(cs).MarkFalse(ClusterImagePolicyConditionKeysInlined, inlineKeysFailedReason, msg) } // MarkInlineKeysOk marks the status saying that the inlining of the keys // had no errors. func (cs *ClusterImagePolicyStatus) MarkInlineKeysOk() { cipCondSet.Manage(cs).MarkTrue(ClusterImagePolicyConditionKeysInlined) } // MarkInlinePoliciesFailed surfaces a failure that we were unable to inline // the policies, either from ConfigMap or from URL. func (cs *ClusterImagePolicyStatus) MarkInlinePoliciesFailed(msg string) { cipCondSet.Manage(cs).MarkFalse(ClusterImagePolicyConditionPoliciesInlined, inlinePoliciesFailedReason, msg) } // MarkInlinePoliciesdOk marks the status saying that the inlining of the // policies had no errors. func (cs *ClusterImagePolicyStatus) MarkInlinePoliciesOk() { cipCondSet.Manage(cs).MarkTrue(ClusterImagePolicyConditionPoliciesInlined) } // MarkCMUpdateFailed surfaces a failure that we were unable to reflect the // CIP into the compiled ConfigMap. func (cs *ClusterImagePolicyStatus) MarkCMUpdateFailed(msg string) { cipCondSet.Manage(cs).MarkFalse(ClusterImagePolicyConditionCMUpdated, updateCMFailedReason, msg) } // MarkCMUpdated marks the status saying that the ConfigMap has been updated. func (cs *ClusterImagePolicyStatus) MarkCMUpdatedOK() { cipCondSet.Manage(cs).MarkTrue(ClusterImagePolicyConditionCMUpdated) } ================================================ FILE: pkg/apis/policy/v1beta1/clusterimagepolicy_types.go ================================================ // 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. package v1beta1 import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" "knative.dev/pkg/kmeta" ) // ClusterImagePolicy defines the images that go through verification // and the authorities used for verification // // +genclient // +genclient:nonNamespaced // +genreconciler:krshapedlogic=true // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type ClusterImagePolicy struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata"` // Spec holds the desired state of the ClusterImagePolicy (from the client). Spec ClusterImagePolicySpec `json:"spec"` // Status represents the current state of the ClusterImagePolicy. // This data may be out of date. // +optional Status ClusterImagePolicyStatus `json:"status,omitempty"` } var ( _ apis.Validatable = (*ClusterImagePolicy)(nil) _ apis.Defaultable = (*ClusterImagePolicy)(nil) _ kmeta.OwnerRefable = (*ClusterImagePolicy)(nil) // Check that the type conforms to the duck Knative Resource shape. _ duckv1.KRShaped = (*ClusterImagePolicy)(nil) ) const ( // ClusterImagePolicyReady is set when the ClusterImagePolicy has been // compiled into the underlying ConfigMap properly. ClusterImagePolicyConditionReady = apis.ConditionReady // ClusterImagePolicyConditionKeysInlined is set to True when all the Keys // have been (Secrets, KMS, etc.) resolved, fetched, validated, and inlined // into the compiled representation. // In failure cases, the Condition will describe the errors in detail. ClusterImagePolicyConditionKeysInlined apis.ConditionType = "KeysInlined" // ClusterImagePolicyConditionPoliciesInlined is set to True when all the // policies have been resolved, fetched, validated, and inlined into the // compiled representation. // In failure cases, the Condition will describe the errors in detail. ClusterImagePolicyConditionPoliciesInlined apis.ConditionType = "PoliciesInlined" // ClusterImagePolicyConditionCMUpdated is set to True when the CIP has been // successfully added into the ConfigMap holding all the compiled CIPs. // In failure cases, the Condition will describe the errors in detail. ClusterImagePolicyConditionCMUpdated apis.ConditionType = "ConfigMapUpdated" ) // GetGroupVersionKind implements kmeta.OwnerRefable func (c *ClusterImagePolicy) GetGroupVersionKind() schema.GroupVersionKind { return SchemeGroupVersion.WithKind("ClusterImagePolicy") } // ClusterImagePolicySpec defines a list of images that should be verified type ClusterImagePolicySpec struct { // Images defines the patterns of image names that should be subject to this policy. Images []ImagePattern `json:"images"` // Authorities defines the rules for discovering and validating signatures. // +optional Authorities []Authority `json:"authorities,omitempty"` // Policy is an optional policy that can be applied against all the // successfully validated Authorities. If no authorities pass, this does // not even get evaluated, as the Policy is considered failed. // +optional Policy *Policy `json:"policy,omitempty"` // Mode controls whether a failing policy will be rejected (not admitted), // or if errors are converted to Warnings. // enforce - Reject (default) // warn - allow but warn // +optional Mode string `json:"mode,omitempty"` // Match allows selecting resources based on their properties. // +optional Match []MatchResource `json:"match,omitempty"` } // ImagePattern defines a pattern and its associated authorties // If multiple patterns match a particular image, then ALL of // those authorities must be satisfied for the image to be admitted. type ImagePattern struct { // Glob defines a globbing pattern. Glob string `json:"glob"` } // The authorities block defines the rules for discovering and // validating signatures. Signatures are // cryptographically verified using one of the "key" or "keyless" // fields. // When multiple authorities are specified, any of them may be used // to source the valid signature we are looking for to admit an // image. type Authority struct { // Name is the name for this authority. Used by the CIP Policy // validator to be able to reference matching signature or attestation // verifications. // If not specified, the name will be authority- Name string `json:"name"` // Key defines the type of key to validate the image. // +optional Key *KeyRef `json:"key,omitempty"` // Keyless sets the configuration to verify the authority against a Fulcio instance. // +optional Keyless *KeylessRef `json:"keyless,omitempty"` // Static specifies that signatures / attestations are not validated but // instead a static policy is applied against matching images. // +optional Static *StaticRef `json:"static,omitempty"` // Sources sets the configuration to specify the sources from where to consume the signatures. // +optional Sources []Source `json:"source,omitempty"` // CTLog sets the configuration to verify the authority against a Rekor instance. // +optional CTLog *TLog `json:"ctlog,omitempty"` // Attestations is a list of individual attestations for this authority, // once the signature for this authority has been verified. // +optional Attestations []Attestation `json:"attestations,omitempty"` // RFC3161Timestamp sets the configuration to verify the signature timestamp against a RFC3161 time-stamping instance. // +optional RFC3161Timestamp *RFC3161Timestamp `json:"rfc3161timestamp,omitempty"` // SignatureFormat specifies the format the authority expects. Supported // formats are "legacy" and "bundle". If not specified, the default // is "legacy" (cosign's default). SignatureFormat string `json:"signatureFormat,omitempty"` } // This references a public verification key stored in // a secret in the cosign-system namespace. // A KeyRef must specify only one of SecretRef, Data or KMS type KeyRef struct { // SecretRef sets a reference to a secret with the key. // +optional SecretRef *v1.SecretReference `json:"secretRef,omitempty"` // Data contains the inline public key. // +optional Data string `json:"data,omitempty"` // KMS contains the KMS url of the public key // Supported formats differ based on the KMS system used. // +optional KMS string `json:"kms,omitempty"` // HashAlgorithm always defaults to sha256 if the algorithm hasn't been explicitly set // +optional HashAlgorithm string `json:"hashAlgorithm,omitempty"` } // StaticRef specifies that signatures / attestations are not validated but // instead a static policy is applied against matching images. type StaticRef struct { // Action defines how to handle a matching policy. Action string `json:"action"` // For fail actions, emit an optional custom message Message string `json:"message,omitempty"` } // Source specifies the location of the signature / attestations. type Source struct { // OCI defines the registry from where to pull the signature / attestations. // +optional OCI string `json:"oci,omitempty"` // SignaturePullSecrets is an optional list of references to secrets in the // same namespace as the deploying resource for pulling any of the signatures // used by this Source. // +optional SignaturePullSecrets []v1.LocalObjectReference `json:"signaturePullSecrets,omitempty"` // TagPrefix is an optional prefix that signature and attestations have. // This is the 'tag based discovery' and in the future once references are // fully supported that should likely be the preferred way to handle these. // +optional TagPrefix *string `json:"tagPrefix,omitempty"` } // TLog specifies the URL to a transparency log that holds // the signature and public key information type TLog struct { // URL sets the url to the rekor instance (by default the public rekor.sigstore.dev) // +optional URL *apis.URL `json:"url,omitempty"` // Use the Public Key from the referred TrustRoot.TLog // +optional TrustRootRef string `json:"trustRootRef,omitempty"` } // KeylessRef contains location of the validating certificate and the identities // against which to verify. KeylessRef will contain either the URL to the verifying // certificate, or it will contain the certificate data inline or in a secret. type KeylessRef struct { // URL defines a url to the keyless instance. // +optional URL *apis.URL `json:"url,omitempty"` // Identities sets a list of identities. Identities []Identity `json:"identities"` // CACert sets a reference to CA certificate // +optional CACert *KeyRef `json:"ca-cert,omitempty"` // Use the Certificate Chain from the referred TrustRoot.CertificateAuthorities and TrustRoot.CTLog // +optional TrustRootRef string `json:"trustRootRef,omitempty"` // InsecureIgnoreSCT omits verifying if a certificate contains an embedded SCT // +optional InsecureIgnoreSCT *bool `json:"insecureIgnoreSCT,omitempty"` } // Attestation defines the type of attestation to validate and optionally // apply a policy decision to it. Authority block is used to verify the // specified attestation types, and if Policy is specified, then it's applied // only after the validation of the Attestation signature has been verified. type Attestation struct { // Name of the attestation. These can then be referenced at the CIP level // policy. Name string `json:"name"` // PredicateType defines which predicate type to verify. Matches cosign verify-attestation options. PredicateType string `json:"predicateType"` // Policy defines all of the matching signatures, and all of // the matching attestations (whose attestations are verified). // +optional Policy *Policy `json:"policy,omitempty"` } // RemotePolicy defines all the properties to fetch a remote policy type RemotePolicy struct { // URL to the policy data. URL apis.URL `json:"url,omitempty"` // Sha256sum defines the exact sha256sum computed out of the 'body' of the http response. Sha256sum string `json:"sha256sum,omitempty"` } // Policy specifies a policy to use for Attestation or the CIP validation (iff // at least one authority matches). // Exactly one of Data, URL, or ConfigMapReference must be specified. type Policy struct { // Which kind of policy this is, currently only rego or cue are supported. // Furthermore, only cue is tested :) Type string `json:"type"` // Data contains the policy definition. // +optional Data string `json:"data,omitempty"` // Remote defines the url to a policy. // +optional Remote *RemotePolicy `json:"remote,omitempty"` // ConfigMapRef defines the reference to a configMap with the policy definition. // +optional ConfigMapRef *ConfigMapReference `json:"configMapRef,omitempty"` // FetchConfigFile controls whether ConfigFile will be fetched and made // available for CIP level policy evaluation. Note that this only gets // evaluated (and hence fetched) iff at least one authority matches. // The ConfigFile will then be available in this format: // https://github.com/opencontainers/image-spec/blob/main/config.md // +optional FetchConfigFile *bool `json:"fetchConfigFile,omitempty"` // IncludeSpec controls whether resource `Spec` will be included and // made available for CIP level policy evaluation. Note that this only gets // evaluated iff at least one authority matches. // Also note that because Spec may be of a different shape depending // on the resource being evaluatied (see MatchResource for filtering) // you might want to configure these to match the policy file to ensure // the shape of the Spec is what you expect when evaling the policy. // +optional IncludeSpec *bool `json:"includeSpec,omitempty"` // IncludeObjectMeta controls whether the ObjectMeta will be included and // made available for CIP level policy evalutation. Note that this only gets // evaluated iff at least one authority matches. // +optional IncludeObjectMeta *bool `json:"includeObjectMeta,omitempty"` // IncludeTypeMeta controls whether the TypeMeta will be included and // made available for CIP level policy evalutation. Note that this only gets // evaluated iff at least one authority matches. // +optional IncludeTypeMeta *bool `json:"includeTypeMeta,omitempty"` } // MatchResource allows selecting resources based on its version, group and resource. // It is also possible to select resources based on a list of matching labels. type MatchResource struct { // +optional metav1.GroupVersionResource `json:",inline"` // +optional ResourceSelector *metav1.LabelSelector `json:"selector,omitempty"` } // ConfigMapReference is cut&paste from SecretReference, but for the life of me // couldn't find one in the public types. If there's one, use it. type ConfigMapReference struct { // Name is unique within a namespace to reference a configmap resource. // +optional Name string `json:"name,omitempty"` // Namespace defines the space within which the configmap name must be unique. // +optional Namespace string `json:"namespace,omitempty"` // Key defines the key to pull from the configmap. // +optional Key string `json:"key,omitempty"` } // Identity may contain the issuer and/or the subject found in the transparency // log. // Issuer/Subject uses a strict match, while IssuerRegExp and SubjectRegExp // apply a regexp for matching. type Identity struct { // Issuer defines the issuer for this identity. // +optional Issuer string `json:"issuer,omitempty"` // Subject defines the subject for this identity. // +optional Subject string `json:"subject,omitempty"` // IssuerRegExp specifies a regular expression to match the issuer for this identity. // +optional IssuerRegExp string `json:"issuerRegExp,omitempty"` // SubjectRegExp specifies a regular expression to match the subject for this identity. // +optional SubjectRegExp string `json:"subjectRegExp,omitempty"` } // RFC3161Timestamp specifies the URL to a RFC3161 time-stamping server that holds // the time-stamped verification for the signature type RFC3161Timestamp struct { // Use the Certificate Chain from the referred TrustRoot.TimeStampAuthorities // +optional TrustRootRef string `json:"trustRootRef,omitempty"` } // ClusterImagePolicyStatus represents the current state of a // ClusterImagePolicy. type ClusterImagePolicyStatus struct { // inherits duck/v1 Status, which currently provides: // * ObservedGeneration - the 'Generation' of the Broker that was last processed by the controller. // * Conditions - the latest available observations of a resource's current state. duckv1.Status `json:",inline"` } // GetStatus retrieves the status of the ClusterImagePolicy. // Implements the KRShaped interface. func (c *ClusterImagePolicy) GetStatus() *duckv1.Status { return &c.Status.Status } // ClusterImagePolicyList is a list of ClusterImagePolicy resources // // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type ClusterImagePolicyList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata"` Items []ClusterImagePolicy `json:"items"` } ================================================ FILE: pkg/apis/policy/v1beta1/clusterimagepolicy_validation.go ================================================ // 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. package v1beta1 import ( "context" "fmt" "net/url" "path/filepath" "regexp" "github.com/sigstore/policy-controller/pkg/apis/glob" "github.com/sigstore/policy-controller/pkg/apis/policy/common" "github.com/sigstore/policy-controller/pkg/apis/signaturealgo" "github.com/sigstore/sigstore/pkg/cryptoutils" "knative.dev/pkg/apis" "knative.dev/pkg/system" policycontrollerconfig "github.com/sigstore/policy-controller/pkg/config" ) // Validate implements apis.Validatable func (c *ClusterImagePolicy) Validate(ctx context.Context) *apis.FieldError { // If we're doing status updates, do not validate the spec. if apis.IsInStatusUpdate(ctx) { return nil } return c.Spec.Validate(ctx).ViaField("spec") } func (spec *ClusterImagePolicySpec) Validate(ctx context.Context) (errors *apis.FieldError) { // Check what the configuration is and act accordingly. pcConfig := policycontrollerconfig.FromContextOrDefaults(ctx) if len(spec.Images) == 0 { errors = errors.Also(apis.ErrMissingField("images")) } for i, image := range spec.Images { errors = errors.Also(image.Validate(ctx).ViaFieldIndex("images", i)) } // Check if PolicyControllerConfig is configured to fail when having empty authorities if len(spec.Authorities) == 0 && pcConfig.FailOnEmptyAuthorities { errors = errors.Also(apis.ErrMissingField("authorities")) } for i, authority := range spec.Authorities { errors = errors.Also(authority.Validate(ctx).ViaFieldIndex("authorities", i)) } if spec.Mode != "" && !common.ValidModes.Has(spec.Mode) { errors = errors.Also(apis.ErrInvalidValue(spec.Mode, "mode", "unsupported mode")) } for i, m := range spec.Match { errors = errors.Also(m.Validate(ctx).ViaFieldIndex("match", i)) } // Note that we're within Spec here so that we can validate that the policy // FetchConfigFile is only set within Spec.Policy. errors = errors.Also(spec.Policy.Validate(apis.WithinSpec(ctx))) return } func (image *ImagePattern) Validate(_ context.Context) *apis.FieldError { if image.Glob == "" { return apis.ErrMissingField("glob") } return ValidateGlob(image.Glob).ViaField("glob") } func (matchResource *MatchResource) Validate(_ context.Context) *apis.FieldError { var errs *apis.FieldError if matchResource.Resource != "" && common.ValidResourceNames.Len() > 0 && !common.ValidResourceNames.Has(matchResource.Resource) { errs = errs.Also(apis.ErrInvalidValue(matchResource.Resource, "resource", "unsupported resource name")) } if matchResource.ResourceSelector != nil && (matchResource.Resource == "" && matchResource.Version == "" && matchResource.Group == "") { errs = errs.Also(apis.ErrInvalidValue(matchResource.Resource, "selector", "selector requires a resource type to match the labels")) } return errs } func (authority *Authority) Validate(ctx context.Context) *apis.FieldError { var errs *apis.FieldError if authority.Key == nil && authority.Keyless == nil && authority.Static == nil { errs = errs.Also(apis.ErrMissingOneOf("key", "keyless", "static")) // Instead of returning all the missing subfields, just return here // to give a more concise and arguably a more meaningful error message. return errs } if (authority.Key != nil && authority.Keyless != nil) || (authority.Key != nil && authority.Static != nil) || (authority.Keyless != nil && authority.Static != nil) { errs = errs.Also(apis.ErrMultipleOneOf("key", "keyless", "static")) // Instead of returning all the missing subfields, just return here // to give a more concise and arguably a more meaningful error message. return errs } if authority.Key != nil { errs = errs.Also(authority.Key.Validate(ctx).ViaField("key")) } if authority.Keyless != nil { errs = errs.Also(authority.Keyless.Validate(ctx).ViaField("keyless")) } if authority.Static != nil { errs = errs.Also(authority.Static.Validate(ctx).ViaField("static")) // Attestations, Sources, RFC3161Timestamp, or CTLog do not make sense with static policy. if len(authority.Attestations) > 0 { errs = errs.Also(apis.ErrMultipleOneOf("static", "attestations")) } if len(authority.Sources) > 0 { errs = errs.Also(apis.ErrMultipleOneOf("static", "source")) } if authority.CTLog != nil { errs = errs.Also(apis.ErrMultipleOneOf("static", "ctlog")) } if authority.RFC3161Timestamp != nil { errs = errs.Also(apis.ErrMultipleOneOf("static", "rfc3161timestamp")) } } if len(authority.Sources) > 1 { errs = errs.Also(apis.ErrInvalidValue("source", "source", "only single source is supported")) } else { // If there are multiple sources, don't complain about each of them. for i, source := range authority.Sources { errs = errs.Also(source.Validate(ctx).ViaFieldIndex("source", i)) } } for _, att := range authority.Attestations { errs = errs.Also(att.Validate(ctx).ViaField("attestations")) } return errs } func (s *StaticRef) Validate(_ context.Context) *apis.FieldError { var errs *apis.FieldError if s.Action == "" { errs = errs.Also(apis.ErrMissingField("action")) } else if !common.ValidStaticRefTypes.Has(s.Action) { errs = errs.Also(apis.ErrInvalidValue(s.Action, "action", "unsupported action")) } return errs } func (key *KeyRef) Validate(_ context.Context) *apis.FieldError { var errs *apis.FieldError if key.Data == "" && key.KMS == "" && key.SecretRef == nil { errs = errs.Also(apis.ErrMissingOneOf("data", "kms", "secretref")) } if key.HashAlgorithm != "" { _, err := signaturealgo.HashAlgorithm(key.HashAlgorithm) if err != nil { errs = errs.Also(apis.ErrInvalidValue(key.HashAlgorithm, "hashAlgorithm")) } } if key.Data != "" { if key.KMS != "" || key.SecretRef != nil { errs = errs.Also(apis.ErrMultipleOneOf("data", "kms", "secretref")) } publicKey, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(key.Data)) if err != nil || publicKey == nil { errs = errs.Also(apis.ErrInvalidValue(key.Data, "data")) } } else if key.KMS != "" && key.SecretRef != nil { errs = errs.Also(apis.ErrMultipleOneOf("data", "kms", "secretref")) } if key.KMS != "" { errs = errs.Also(common.ValidateKMS(key.KMS).ViaField("kms")) } if key.SecretRef != nil && key.SecretRef.Namespace != "" && key.SecretRef.Namespace != system.Namespace() { errs = errs.Also(apis.ErrInvalidValue(key.SecretRef.Namespace, "secretref.namespace", "secretref.namespace is invalid. If set, it should use the same namespace where the policy-controller was deployed")) } return errs } func (keyless *KeylessRef) Validate(ctx context.Context) *apis.FieldError { var errs *apis.FieldError if keyless.URL == nil && keyless.CACert == nil { errs = errs.Also(apis.ErrMissingOneOf("url", "ca-cert")) } // TODO: Are these really mutually exclusive? if keyless.URL != nil && keyless.CACert != nil { errs = errs.Also(apis.ErrMultipleOneOf("url", "ca-cert")) } if keyless.CACert != nil { errs = errs.Also(keyless.DeepCopy().CACert.Validate(ctx).ViaField("ca-cert")) } // Check that identities is specified. if len(keyless.Identities) == 0 { errs = errs.Also(apis.ErrMissingField("identities")) } for i, identity := range keyless.Identities { errs = errs.Also(identity.Validate(ctx).ViaFieldIndex("identities", i)) } return errs } func (source *Source) Validate(_ context.Context) *apis.FieldError { var errs *apis.FieldError if source.OCI != "" { if err := common.ValidateOCI(source.OCI); err != nil { errs = errs.Also(apis.ErrInvalidValue(source.OCI, "oci", err.Error())) } } if len(source.SignaturePullSecrets) > 0 { for i, secret := range source.SignaturePullSecrets { if secret.Name == "" { errs = errs.Also(apis.ErrMissingField("name")).ViaFieldIndex("signaturePullSecrets", i) } } } return errs } func (a *Attestation) Validate(ctx context.Context) *apis.FieldError { var errs *apis.FieldError if a.Name == "" { errs = errs.Also(apis.ErrMissingField("name")) } switch { case a.PredicateType == "": // This is just straight up missing, so error out. errs = errs.Also(apis.ErrMissingField("predicateType")) case common.ValidPredicateTypes.Has(a.PredicateType): // Ok, it's a valid, deprecated short form. It's fine for now, but // should remove it soon because it is very error prone, so warn. errs = errs.Also(apis.ErrInvalidValue(a.PredicateType, "predicateType", "deprecated value, please use RFC 3986 conformant values").At(apis.WarningLevel)) default: // This could be a fully specified URL, so check for that here. if _, err := url.ParseRequestURI(a.PredicateType); err != nil { // This is fine for now, but should remove it soon because it is // very error prone. errs = errs.Also(apis.ErrInvalidValue(a.PredicateType, "predicateType", "deprecated value, please use RFC 3986 conformant values").At(apis.WarningLevel)) } } errs = errs.Also(a.Policy.Validate(ctx).ViaField("policy")) return errs } func (cmr *ConfigMapReference) Validate(_ context.Context) *apis.FieldError { var errs *apis.FieldError if cmr.Name == "" { errs = errs.Also(apis.ErrMissingField("name")) } if cmr.Key == "" { errs = errs.Also(apis.ErrMissingField("key")) } return errs } func (r *RemotePolicy) Validate(_ context.Context) *apis.FieldError { var errs *apis.FieldError urlObj := r.URL u, err := url.Parse(urlObj.String()) if err != nil || (err == nil && (u.Host == "" || u.Scheme == "" || u.Scheme != "https")) { errs = errs.Also(apis.ErrInvalidValue(r.URL.String(), "url", "url valid is invalid. host and https scheme are expected")) } if r.Sha256sum == "" { errs = errs.Also(apis.ErrMissingField("sha256sum")) } return errs } func (p *Policy) Validate(ctx context.Context) *apis.FieldError { if p == nil { return nil } var errs *apis.FieldError if p.Type != "cue" && p.Type != "rego" { errs = errs.Also(apis.ErrInvalidValue(p.Type, "type", "only [cue,rego] are supported at the moment")) } if p.Data == "" && p.ConfigMapRef == nil && p.Remote == nil { errs = errs.Also(apis.ErrMissingField("data", "configMapRef", "remote")) } if p.Data != "" && p.ConfigMapRef != nil && p.Remote != nil { errs = errs.Also(apis.ErrMultipleOneOf("data", "configMapRef", "remote")) } if (p.Data != "" && p.ConfigMapRef != nil) || (p.Data != "" && p.Remote != nil) || (p.ConfigMapRef != nil && p.Remote != nil) { errs = errs.Also(apis.ErrMultipleOneOf("data", "configMapRef", "remote")) } if p.Remote != nil { errs = errs.Also(p.Remote.Validate(ctx).ViaField("remote")) } if p.ConfigMapRef != nil { errs = errs.Also(p.ConfigMapRef.Validate(ctx).ViaField("configMapRef")) } if !apis.IsInSpec(ctx) && p.FetchConfigFile != nil { errs = errs.Also(apis.ErrDisallowedFields("fetchConfigFile")) } if !apis.IsInSpec(ctx) && p.IncludeSpec != nil { errs = errs.Also(apis.ErrDisallowedFields("includeSpec")) } if !apis.IsInSpec(ctx) && p.IncludeObjectMeta != nil { errs = errs.Also(apis.ErrDisallowedFields("includeObjectMeta")) } if !apis.IsInSpec(ctx) && p.IncludeTypeMeta != nil { errs = errs.Also(apis.ErrDisallowedFields("includeTypeMeta")) } // TODO(vaikas): How to validate the cue / rego bytes here (data). return errs } func (identity *Identity) Validate(_ context.Context) *apis.FieldError { var errs *apis.FieldError if identity.Issuer != "" && identity.IssuerRegExp != "" { errs = errs.Also(apis.ErrMultipleOneOf("issuer", "issuerRegExp")) } if identity.Subject != "" && identity.SubjectRegExp != "" { errs = errs.Also(apis.ErrMultipleOneOf("subject", "subjectRegExp")) } if identity.IssuerRegExp != "" { errs = errs.Also(ValidateRegex(identity.IssuerRegExp).ViaField("issuerRegExp")) } if identity.SubjectRegExp != "" { errs = errs.Also(ValidateRegex(identity.SubjectRegExp).ViaField("subjectRegExp")) } if identity.SubjectRegExp == "" && identity.Subject == "" { errs = errs.Also(apis.ErrMissingField("subject", "subjectRegExp")) } if identity.IssuerRegExp == "" && identity.Issuer == "" { errs = errs.Also(apis.ErrMissingField("issuer", "issuerRegExp")) } return errs } // ValidateGlob glob compilation by testing against empty string func ValidateGlob(g string) *apis.FieldError { if _, err := filepath.Match(g, ""); err != nil { return apis.ErrInvalidValue(g, apis.CurrentField, fmt.Sprintf("glob is invalid: %v", err)) } if _, err := glob.Compile(g); err != nil { return apis.ErrInvalidValue(g, apis.CurrentField, fmt.Sprintf("glob is invalid: %v", err)) } return nil } func ValidateRegex(regex string) *apis.FieldError { _, err := regexp.Compile(regex) if err != nil { return apis.ErrInvalidValue(regex, apis.CurrentField, fmt.Sprintf("regex is invalid: %v", err)) } return nil } ================================================ FILE: pkg/apis/policy/v1beta1/clusterimagepolicy_validation_test.go ================================================ // 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. package v1beta1 import ( "context" "os" "strings" "testing" "github.com/sigstore/policy-controller/pkg/apis/policy/common" "github.com/sigstore/policy-controller/pkg/apis/signaturealgo" "github.com/stretchr/testify/require" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/pkg/apis" "knative.dev/pkg/ptr" policycontrollerconfig "github.com/sigstore/policy-controller/pkg/config" ) const validPublicKey = "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaEOVJCFtduYr3xqTxeRWSW32CY/s\nTBNZj4oIUPl8JvhVPJ1TKDPlNcuT4YphSt6t3yOmMvkdQbCj8broX6vijw==\n-----END PUBLIC KEY-----" const ( signatureSHA512HashAlgorithm = "sha512" signatureSHAInvalidHashAlgorithm = "shaInvalid" ) func TestImagePatternValidation(t *testing.T) { tests := []struct { name string errorString string policy ClusterImagePolicy }{{ name: "Should fail when glob is not present", errorString: "missing field(s): spec.authorities, spec.images[0].glob", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ {}, }, }, }, }, { name: "Glob should fail with invalid glob", errorString: "invalid value: [: spec.images[0].glob\nglob is invalid: syntax error in pattern\nmissing field(s): spec.authorities", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "[", }, }, }, }, }, { name: "Glob should fail with invalid regexp", errorString: "invalid value: $FOO*: spec.images[0].glob\nglob is invalid: invalid glob \"$FOO*\"\nmissing field(s): spec.authorities", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "$FOO*", }, }, }, }, }, { name: "missing image and authorities in the spec", errorString: "missing field(s): spec.authorities, spec.images", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{}, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { testContext := policycontrollerconfig.ToContext(context.TODO(), &policycontrollerconfig.PolicyControllerConfig{NoMatchPolicy: policycontrollerconfig.AllowAll, FailOnEmptyAuthorities: true}) err := test.policy.Validate(testContext) validateError(t, test.errorString, "", err) }) } } func TestKeyValidation(t *testing.T) { os.Setenv("SYSTEM_NAMESPACE", "cosign-system") tests := []struct { name string errorString string policy ClusterImagePolicy }{{ name: "Should fail when key has multiple properties", errorString: "expected exactly one, got both: spec.authorities[0].key.data, spec.authorities[0].key.kms, spec.authorities[0].key.secretref", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "myglob", }, }, Authorities: []Authority{ { Key: &KeyRef{ Data: "-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEaEOVJCFtduYr3xqTxeRWSW32CY/s\nTBNZj4oIUPl8JvhVPJ1TKDPlNcuT4YphSt6t3yOmMvkdQbCj8broX6vijw==\n-----END PUBLIC KEY-----", KMS: "hashivault://key/path", }, }, }, }, }, }, { name: "Should fail when key has malformed pubkey data", errorString: "invalid value: ---some key data----: spec.authorities[0].key.data", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "myglob", }, }, Authorities: []Authority{ { Key: &KeyRef{ Data: "---some key data----", }, }, }, }, }, }, { name: "Should fail when key secretref has an invalid value for the namespace", errorString: "invalid value: invalid: spec.authorities[0].key.secretref.namespace\nsecretref.namespace is invalid. If set, it should use the same namespace where the policy-controller was deployed", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "myglob", }, }, Authorities: []Authority{ { Key: &KeyRef{ SecretRef: &v1.SecretReference{ Name: "test", Namespace: "invalid", }, }, }, }, }, }, }, { name: "Should fail when key is empty", errorString: "expected exactly one, got neither: spec.authorities[0].key.data, spec.authorities[0].key.kms, spec.authorities[0].key.secretref", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "myglob*", }, }, Authorities: []Authority{ { Key: &KeyRef{}, }, }, }, }, }, { name: "Should fail with invalid AWS KMS for Keyful", errorString: "invalid value: awskms://localhost:8888/arn:butnotvalid: spec.authorities[0].key.kms\nkms key should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "awskms://localhost:8888/arn:butnotvalid"}, Sources: []Source{{OCI: "registry.example.com"}}, }, }, }, }, }, { name: "Should fail with invalid OCI value", errorString: "invalid value: registry.example.com/repo/*: spec.authorities[0].source[0].oci\nrepository can only contain the characters `abcdefghijklmnopqrstuvwxyz0123456789_-./`: repo/*", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Sources: []Source{{OCI: "registry.example.com/repo/*"}}, }, }, }, }, }, { name: "Should fail with invalid OCI value usign wrong characters", errorString: "invalid value: re@gistry/reponame: spec.authorities[0].source[0].oci\nregistries must be valid RFC 3986 URI authorities: re@gistry/reponame", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Sources: []Source{{OCI: "re@gistry/reponame"}}, }, }, }, }, }, { name: "Should pass with valid OCI repository name", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Sources: []Source{{OCI: "gcr.io/google.com/project/hello-world"}}, }, }, }, }, }, { name: "Should pass with valid OCI repository name", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Sources: []Source{{OCI: "registry.example.com/repository"}}, }, }, }, }, }, { name: "Should pass when key has only one property: %v", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "yepanotherglob", }, }, Authorities: []Authority{ { Key: &KeyRef{ KMS: "hashivault://key/path", }, }, }, }, }, }, { name: "Glob should pass with exact digest image", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "ghcr.io/foo@sha256:5504f2a95018e3d8a52d80d9e1a128c6ea337581808ff9fe96f5628ce2336350", }, }, Authorities: []Authority{ { Key: &KeyRef{ KMS: "hashivault://key/path", }, }, }, }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { err := test.policy.Validate(context.TODO()) validateError(t, test.errorString, "", err) }) } } func TestKeylessValidation(t *testing.T) { tests := []struct { name string errorString string policy ClusterImagePolicy }{{ name: "Should fail when keyless is empty", errorString: "expected exactly one, got neither: spec.authorities[0].keyless.ca-cert, spec.authorities[0].keyless.url\nmissing field(s): spec.authorities[0].keyless.identities", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{}, }, }, }, }, }, { name: "Should fail when keyless has multiple properties", errorString: "expected exactly one, got both: spec.authorities[0].keyless.ca-cert, spec.authorities[0].keyless.url\nmissing field(s): spec.authorities[0].keyless.identities", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, CACert: &KeyRef{ Data: validPublicKey, }, }, }, }, }, }, }, { name: "Should warn when valid keyless ref is specified, but no identities given", errorString: "missing field(s): spec.authorities[0].keyless.identities", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, }, }, }, }, }, }, { name: "Should pass when valid keyless ref is specified", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{ { Subject: "somesubject", Issuer: "someissuer", }, }, }, }, }, }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { err := test.policy.Validate(context.TODO()) validateError(t, test.errorString, "", err) }) } } func TestStaticValidation(t *testing.T) { tests := []struct { name string errorString string policy ClusterImagePolicy }{{ name: "Should fail when static is empty", errorString: "missing field(s): spec.authorities[0].static.action", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Static: &StaticRef{}, }, }, }, }, }, { name: "Should fail when action is invalid", errorString: "invalid value: garbage: spec.authorities[0].static.action\nunsupported action", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Static: &StaticRef{Action: "garbage"}, }, }, }, }, }, { name: "Works with pass", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Static: &StaticRef{Action: "pass"}, }, }, }, }, }, { name: "Works with pass, and Spec.Policy.FetchConfigFile", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Static: &StaticRef{Action: "pass"}, }, }, Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, FetchConfigFile: ptr.Bool(true), }, }, }, }, { name: "Works with pass, and Spec.Policy.IncludeSpec", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Static: &StaticRef{Action: "pass"}, }, }, Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, IncludeSpec: ptr.Bool(true), }, }, }, }, { name: "Works with pass, and Spec.Policy.IncludeObjectMeta", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Static: &StaticRef{Action: "pass"}, }, }, Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, IncludeObjectMeta: ptr.Bool(true), }, }, }, }, { name: "Works with pass, and Spec.Policy.IncludeTypeMeta", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Static: &StaticRef{Action: "pass"}, }, }, Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, IncludeTypeMeta: ptr.Bool(true), }, }, }, }, { name: "Works with fail", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Static: &StaticRef{Action: "fail"}, }, }, }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { err := test.policy.Validate(context.TODO()) validateError(t, test.errorString, "", err) }) } } func TestModeValidation(t *testing.T) { tests := []struct { name string errorString string mode string }{{ name: "Should work when mode is empty", mode: "", }, { name: "Should work with mode enforce", mode: "enforce", }, { name: "Should work with mode warn", mode: "warn", }, { name: "Should not work with mode garbage", mode: "garbage", errorString: "invalid value: garbage: spec.mode\nunsupported mode", }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { policy := ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "globbityglob"}}, Authorities: []Authority{{Static: &StaticRef{Action: "pass"}}}, Mode: test.mode, }, } err := policy.Validate(context.TODO()) validateError(t, test.errorString, "", err) }) } } func TestAuthoritiesValidation(t *testing.T) { tests := []struct { name string errorString string warnString string policy ClusterImagePolicy }{{ name: "Should fail when authority is empty", errorString: "expected exactly one, got neither: spec.authorities[0].key, spec.authorities[0].keyless, spec.authorities[0].static", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ {}, }, }, }, }, { name: "Should fail when key/keyless specified", errorString: "expected exactly one, got both: spec.authorities[0].key, spec.authorities[0].keyless, spec.authorities[0].static", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Key: &KeyRef{Data: validPublicKey}, Keyless: &KeylessRef{URL: apis.HTTPS("fulcio.sigstore.dev")}, }, }, }, }, }, { name: "Should fail when key/static specified", errorString: "expected exactly one, got both: spec.authorities[0].key, spec.authorities[0].keyless, spec.authorities[0].static", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Key: &KeyRef{Data: validPublicKey}, Static: &StaticRef{Action: "pass"}, }, }, }, }, }, { name: "Should fail when keyless/static specified", errorString: "expected exactly one, got both: spec.authorities[0].key, spec.authorities[0].keyless, spec.authorities[0].static", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Static: &StaticRef{Action: "fail"}, Keyless: &KeylessRef{URL: apis.HTTPS("fulcio.sigstore.dev")}, }, }, }, }, }, { name: "Should fail when key/keyless/static specified", errorString: "expected exactly one, got both: spec.authorities[0].key, spec.authorities[0].keyless, spec.authorities[0].static", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Key: &KeyRef{Data: validPublicKey}, Keyless: &KeylessRef{URL: apis.HTTPS("fulcio.sigstore.dev")}, Static: &StaticRef{Action: "fail"}, }, }, }, }, }, { name: "Should fail when static and sources,attestations, and ctlog is specified, warn about legacy short predicate type", errorString: "expected exactly one, got both: spec.authorities[0].attestations, spec.authorities[0].ctlog, spec.authorities[0].source, spec.authorities[0].static", warnString: "invalid value: vuln: spec.authorities[0].attestations.predicateType\ndeprecated value, please use RFC 3986 conformant values", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Static: &StaticRef{Action: "fail"}, Attestations: []Attestation{{Name: "first", PredicateType: "vuln"}}, Sources: []Source{ { OCI: "registry1", SignaturePullSecrets: []v1.LocalObjectReference{ {Name: "placeholder"}, }, }, }, CTLog: &TLog{}, }, }, }, }, }, { name: "Should fail with invalid kms prefix", errorString: "invalid value: fookms://localhost:8888/xpa:butnotvalid: spec.authorities[0].key.kms\nmalformed KMS format, should be prefixed by any of the supported providers: [awskms:// azurekms:// hashivault:// gcpkms://]", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "fookms://localhost:8888/xpa:butnotvalid"}, Sources: []Source{{OCI: "registry.example.com"}}, }, }, }, }, }, { name: "Should fail when static and sources,attestations, and rfc3161timestamp is specified", errorString: "expected exactly one, got both: spec.authorities[0].attestations, spec.authorities[0].rfc3161timestamp, spec.authorities[0].source, spec.authorities[0].static", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Static: &StaticRef{Action: "fail"}, Attestations: []Attestation{{Name: "first", PredicateType: "https://cosign.sigstore.dev/attestation/vuln/v1"}}, Sources: []Source{ { OCI: "registry1", SignaturePullSecrets: []v1.LocalObjectReference{ {Name: "placeholder"}, }, }, }, RFC3161Timestamp: &RFC3161Timestamp{}, }, }, }, }, }, { name: "Should fail when authorities is empty", errorString: "missing field(s): spec.authorities", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{}, }, }, }, { name: "Should pass when source oci is present", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Sources: []Source{{OCI: "registry.example.com"}}, }, }, }, }, }, { name: "Should pass with multiple source oci is present", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Sources: []Source{ {OCI: "registry1"}, }, }, }, }, }, }, { name: "Should fail with multiple source oci is present", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Sources: []Source{ {OCI: "registry1"}, {OCI: "registry2"}, }, }, }, }, }, errorString: "invalid value: source: spec.authorities[0].source\nonly single source is supported", }, { name: "Should fail with invalid AWS KMS for Keyful", errorString: "invalid value: awskms://localhost:8888/arn:butnotvalid: spec.authorities[0].key.kms\nkms key should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "awskms://localhost:8888/arn:butnotvalid"}, Sources: []Source{{OCI: "registry.example.com"}}, }, }, }, }, }, { name: "Should fail with invalid AWS KMS for Keyless", errorString: "invalid value: awskms://localhost:8888/arn:butnotvalid: spec.authorities[0].keyless.ca-cert.kms\nkms key should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)\nmissing field(s): spec.authorities[0].keyless.identities", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Keyless: &KeylessRef{CACert: &KeyRef{KMS: "awskms://localhost:8888/arn:butnotvalid"}}, }, }, }, }, }, { name: "Should pass with attestations present", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Attestations: []Attestation{ {Name: "first", PredicateType: "https://cosign.sigstore.dev/attestation/vuln/v1"}, {Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, }, }, }, }, }, }, }, }, { name: "Should fail with attestations policy specifying fetchConfigFile", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Attestations: []Attestation{ {Name: "first", PredicateType: "https://cosign.sigstore.dev/attestation/vuln/v1"}, {Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, FetchConfigFile: ptr.Bool(true), }, }, }, }, }, }, }, errorString: "must not set the field(s): spec.authorities[0].attestations.policy.fetchConfigFile", }, { name: "Should fail with attestations policy specifying includeSpec", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Attestations: []Attestation{ {Name: "first", PredicateType: "https://cosign.sigstore.dev/attestation/vuln/v1"}, {Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, IncludeSpec: ptr.Bool(true), }, }, }, }, }, }, }, errorString: "must not set the field(s): spec.authorities[0].attestations.policy.includeSpec", }, { name: "Should fail with attestations policy specifying includeObjectMeta", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Attestations: []Attestation{ {Name: "first", PredicateType: "https://cosign.sigstore.dev/attestation/vuln/v1"}, {Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, IncludeObjectMeta: ptr.Bool(true), }, }, }, }, }, }, }, errorString: "must not set the field(s): spec.authorities[0].attestations.policy.includeObjectMeta", }, { name: "Should fail with attestations policy specifying includeTypeMeta", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "gcr.io/*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Attestations: []Attestation{ {Name: "first", PredicateType: "https://cosign.sigstore.dev/attestation/vuln/v1"}, {Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, IncludeTypeMeta: ptr.Bool(true), }, }, }, }, }, }, }, errorString: "must not set the field(s): spec.authorities[0].attestations.policy.includeTypeMeta", }, { name: "Should fail with signaturePullSecret name empty", errorString: "missing field(s): spec.authorities[0].source[0].signaturePullSecrets[0].name", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Sources: []Source{ { OCI: "registry1", SignaturePullSecrets: []v1.LocalObjectReference{ {Name: ""}, }, }, }, }, }, }, }, }, { name: "Should pass with signaturePullSecret name filled", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Sources: []Source{ { OCI: "registry1", SignaturePullSecrets: []v1.LocalObjectReference{ {Name: "testPullSecrets"}, }, }, }, }, }, }, }, }, { name: "Should fail with invalid signature hash algorithm", errorString: "invalid value: " + signatureSHAInvalidHashAlgorithm + ": spec.authorities[0].key.hashAlgorithm", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path", HashAlgorithm: signatureSHAInvalidHashAlgorithm}, }, }, }, }, }, { name: "Should pass with sha256 signature hash algorithm", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path", HashAlgorithm: signaturealgo.DefaultSignatureAlgorithm}, Sources: []Source{ { OCI: "registry1", SignaturePullSecrets: []v1.LocalObjectReference{ {Name: "testPullSecrets"}, }, }, }, }, }, }, }, }, { name: "Should pass with sha512 signature hash algorithm", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path", HashAlgorithm: signatureSHA512HashAlgorithm}, Sources: []Source{ { OCI: "registry1", SignaturePullSecrets: []v1.LocalObjectReference{ {Name: "testPullSecrets"}, }, }, }, }, }, }, }, }, { name: "Should pass when source oci is empty", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "*"}}, Authorities: []Authority{ { Key: &KeyRef{KMS: "hashivault://key/path"}, Sources: []Source{{OCI: ""}}, }, }, }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { testContext := policycontrollerconfig.ToContext(context.TODO(), &policycontrollerconfig.PolicyControllerConfig{NoMatchPolicy: policycontrollerconfig.AllowAll, FailOnEmptyAuthorities: true}) err := test.policy.Validate(testContext) validateError(t, test.errorString, test.warnString, err) }) } } func TestEmptyAuthoritiesValidation(t *testing.T) { tests := []struct { name string errorString string policy ClusterImagePolicy }{{ name: "Should pass when Authorities is empty", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{{Glob: "*"}}, Authorities: []Authority{}, }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { testContext := policycontrollerconfig.ToContext(context.TODO(), &policycontrollerconfig.PolicyControllerConfig{NoMatchPolicy: policycontrollerconfig.AllowAll, FailOnEmptyAuthorities: false}) err := test.policy.Validate(testContext) validateError(t, test.errorString, "", err) }) } } func TestAttestationsValidation(t *testing.T) { tests := []struct { name string errorString string warnString string attestation Attestation }{{ name: "https://cosign.sigstore.dev/attestation/vuln/v1", attestation: Attestation{Name: "first", PredicateType: "https://cosign.sigstore.dev/attestation/vuln/v1"}, }, { name: "fully specified URL", attestation: Attestation{Name: "fullyspecified", PredicateType: "https://cyclonedx.org/schema"}, }, { name: "missing name", attestation: Attestation{PredicateType: "https://cosign.sigstore.dev/attestation/vuln/v1"}, errorString: "missing field(s): name", }, { name: "missing predicatetype", attestation: Attestation{Name: "first"}, errorString: "missing field(s): predicateType", }, { name: "invalid predicatetype", attestation: Attestation{Name: "first", PredicateType: "notsupported"}, warnString: "invalid value: notsupported: predicateType\ndeprecated value, please use RFC 3986 conformant values", }, { name: "custom with invalid policy type", attestation: Attestation{Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "not-cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, }, }, errorString: "invalid value: not-cue: policy.type\nonly [cue,rego] are supported at the moment", }, { name: "custom with missing policy data, url and configMapRef", attestation: Attestation{Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", }, }, errorString: "missing field(s): policy.configMapRef, policy.data, policy.remote", }, { name: "custom with both policy data and configMapRef", attestation: Attestation{Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, ConfigMapRef: &ConfigMapReference{ Name: "cmname", Key: "keyname", }, }, }, errorString: "expected exactly one, got both: policy.configMapRef, policy.data, policy.remote", }, { name: "custom with both policy data, url and configMapRef", attestation: Attestation{Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, ConfigMapRef: &ConfigMapReference{ Name: "cmname", Key: "keyname", }, Remote: &RemotePolicy{ URL: *apis.HTTPS("example.com"), Sha256sum: "123123123", }, }, }, errorString: "expected exactly one, got both: policy.configMapRef, policy.data, policy.remote", }, { name: "custom with both policy url", attestation: Attestation{Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", Remote: &RemotePolicy{ URL: *apis.HTTPS("example.com"), Sha256sum: "123123123", }, }, }, }, { name: "custom with invalid policy url scheme", attestation: Attestation{Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", Remote: &RemotePolicy{ URL: *apis.HTTP("example.com"), Sha256sum: "123123123", }, }, }, errorString: "invalid value: http://example.com: policy.remote.url\nurl valid is invalid. host and https scheme are expected", }, { name: "custom with invalid configMapRef, missing key", attestation: Attestation{Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", ConfigMapRef: &ConfigMapReference{ Name: "cmname", }, }, }, errorString: "missing field(s): policy.configMapRef.key", }, { name: "custom with policy", attestation: Attestation{Name: "second", PredicateType: "https://cosign.sigstore.dev/attestation/v1", Policy: &Policy{ Type: "cue", Data: `predicateType: "cosign.sigstore.dev/attestation/vuln/v1"`, }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { err := test.attestation.Validate(context.TODO()) validateError(t, test.errorString, test.warnString, err) }) } } func TestIdentitiesValidation(t *testing.T) { tests := []struct { name string errorString string policy ClusterImagePolicy }{{ name: "Should pass with identities", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{{SubjectRegExp: ".*subject.*", IssuerRegExp: ".*issuer.*"}}, }, }, }, }, }, }, { name: "Should warn when identities fields are empty", errorString: "missing field(s): spec.authorities[0].keyless.identities[0].issuer, spec.authorities[0].keyless.identities[0].issuerRegExp, spec.authorities[0].keyless.identities[0].subject, spec.authorities[0].keyless.identities[0].subjectRegExp", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{{Issuer: ""}}, }, }, }, }, }, }, { name: "Should fail with both issuer and issuerRegExp", errorString: "expected exactly one, got both: spec.authorities[0].keyless.identities[0].issuer, spec.authorities[0].keyless.identities[0].issuerRegExp", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{{Issuer: "issuer", IssuerRegExp: "issuerregexp", Subject: "subject"}}, }, }, }, }, }, }, { name: "Should fail with both subject and subjectRegExp", errorString: "expected exactly one, got both: spec.authorities[0].keyless.identities[0].subject, spec.authorities[0].keyless.identities[0].subjectRegExp", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{{Subject: "subject", SubjectRegExp: "subjectregexp", Issuer: "issuer"}}, }, }, }, }, }, }, { name: "Should fail when issuer has invalid regex", errorString: "invalid value: ****: spec.authorities[0].keyless.identities[0].issuerRegExp\nregex is invalid: error parsing regexp: missing argument to repetition operator: `*`", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{{IssuerRegExp: "****", Subject: "subject"}}, }, }, }, }, }, }, { name: "Should warn when issuer or issuerRegExp is missing", errorString: "missing field(s): spec.authorities[0].keyless.identities[0].issuer, spec.authorities[0].keyless.identities[0].issuerRegExp", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{{Subject: "subject"}}, }, }, }, }, }, }, { name: "Should warn when subject or subjectRegExp is missing", errorString: "missing field(s): spec.authorities[0].keyless.identities[0].subject, spec.authorities[0].keyless.identities[0].subjectRegExp", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{{Issuer: "issuer"}}, }, }, }, }, }, }, { name: "Should fail when subject has invalid regex", errorString: "invalid value: ****: spec.authorities[0].keyless.identities[0].subjectRegExp\nregex is invalid: error parsing regexp: missing argument to repetition operator: `*`", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{{Issuer: "issuer", SubjectRegExp: "****"}}, }, }, }, }, }, }, { name: "Should pass when subject and issuer have valid regex", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{{SubjectRegExp: ".*subject.*", IssuerRegExp: ".*issuer.*"}}, }, }, }, }, }, }, { name: "Should pass when identities is valid", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{ { Issuer: "some issuer", Subject: "some subject", }, }, }, }, }, }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { err := test.policy.Validate(context.TODO()) validateError(t, test.errorString, "", err) }) } } func TestAWSKMSValidation(t *testing.T) { // Note the error messages betweeen the kms / cacert validation is // identical, with the only difference being `kms` or `ca-cert.kms`. Reason // for the ca-cert.kms is because it's embedded within the ca-cert that // we pass in. So we put a KMSORCACERT into the err string that we then // replace based on the tests so we don't have to write identical tests // for both of them. tests := []struct { name string errorString string kms string }{{ name: "malformed, only 2 slashes ", errorString: "invalid value: awskms://1234abcd-12ab-34cd-56ef-1234567890ab: KMSORCACERT\nmalformed AWS KMS format 'awskms://$ENDPOINT/$KEYID', should be conformant with KMS standard documented here: https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#key-id", kms: "awskms://1234abcd-12ab-34cd-56ef-1234567890ab", }, { name: "fails with invalid host", errorString: "invalid value: awskms://localhost:::4566/alias/exampleAlias: KMSORCACERT\nmalformed endpoint: address localhost:::4566: too many colons in address", kms: "awskms://localhost:::4566/alias/exampleAlias", }, { name: "fails with non-arn alias", errorString: "invalid value: awskms://localhost:4566/alias/exampleAlias: KMSORCACERT\nfailed to parse either key or alias arn: arn: invalid prefix", kms: "awskms://localhost:4566/alias/exampleAlias", }, { name: "Should fail when arn is invalid", errorString: "invalid value: awskms://localhost:4566/arn:sonotvalid: KMSORCACERT\nkms key should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)", kms: "awskms://localhost:4566/arn:sonotvalid", }, { name: "Should fail with key is invalid", errorString: "invalid value: awskms://arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab: KMSORCACERT\nkms key should be in the format awskms://[ENDPOINT]/[ID/ALIAS/ARN] (endpoint optional)", kms: "awskms://arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", }, { name: "works with valid arn key and endpoint", kms: "awskms://localhost:4566/arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", }, { name: "works with valid arn key and no endpoint", kms: "awskms:///arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab", }, { name: "works with valid arn alias and endpoint", kms: "awskms://localhost:4566/arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias", }, { name: "works with valid arn alias and no endpoint", kms: "awskms:///arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias", }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { // First test with KeyRef keyRef := KeyRef{KMS: test.kms} err := keyRef.Validate(context.TODO()) kmsErrString := strings.Replace(test.errorString, "KMSORCACERT", "kms", 1) validateError(t, kmsErrString, "", err) // Then with Keyless with CACert as KeyRef keylessRef := KeylessRef{CACert: &keyRef, Identities: []Identity{{Subject: "testsubject", Issuer: "testIssuer"}}} err = keylessRef.Validate(context.TODO()) caCertErrString := strings.Replace(test.errorString, "KMSORCACERT", "ca-cert.kms", 1) validateError(t, caCertErrString, "", err) }) } } // validateError checks the given error against wanted error/warning strings // if either is "" then it's assume an error/warning is not wanted and if // one is given, will error. // nolint since currently we do not have warnings we expect, but having this // around makes it easier to add warning validations in the future. // //nolint:all func validateError(t *testing.T, wantErrStr, wantWarnStr string, fe *apis.FieldError) { t.Helper() // Grab warning and check it first warnFE := fe.Filter(apis.WarningLevel) if wantWarnStr != "" { require.NotNil(t, warnFE) require.EqualError(t, warnFE, wantWarnStr) } else { require.Nil(t, warnFE) } // Then grab error and check it errFE := fe.Filter(apis.ErrorLevel) if wantErrStr != "" { require.NotNil(t, errFE) require.EqualError(t, errFE, wantErrStr) } else { require.Nil(t, errFE) } } func TestMatchValidation(t *testing.T) { // Add a "supported" resource name that we'll use to test things. common.ValidResourceNames.Insert("supported") tests := []struct { name string errorString string policy ClusterImagePolicy }{{ name: "Should pass with identities", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{{SubjectRegExp: ".*subject.*", IssuerRegExp: ".*issuer.*"}}, }, }, }, }, }, }, { name: "Should pass with match label selector", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Match: []MatchResource{ { GroupVersionResource: metav1.GroupVersionResource{ Group: "apps", Version: "v1", Resource: "supported", }, ResourceSelector: &metav1.LabelSelector{ MatchLabels: map[string]string{"a": "b", "c": "d"}, }, }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{ { Issuer: "some issuer", Subject: "some subject", }, }, }, }, }, }, }, }, { name: "Should pass with match resource types", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Match: []MatchResource{ { GroupVersionResource: metav1.GroupVersionResource{ Group: "apps", Version: "v1", Resource: "supported", }, }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, InsecureIgnoreSCT: ptr.Bool(true), Identities: []Identity{ { Issuer: "some issuer", Subject: "some subject", }, }, }, }, }, }, }, }, { name: "Should fail with invalid match resource type", errorString: "invalid value: myobject: spec.match[0].resource\nunsupported resource name", policy: ClusterImagePolicy{ Spec: ClusterImagePolicySpec{ Images: []ImagePattern{ { Glob: "globbityglob", }, }, Match: []MatchResource{ { GroupVersionResource: metav1.GroupVersionResource{ Group: "", Version: "v1", Resource: "myobject", }, }, }, Authorities: []Authority{ { Keyless: &KeylessRef{ URL: &apis.URL{ Host: "myhost", }, Identities: []Identity{ { Issuer: "some issuer", Subject: "some subject", }, }, }, }, }, }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { err := test.policy.Validate(context.TODO()) validateError(t, test.errorString, "", err) }) } } func TestIgnoreStatusUpdates(t *testing.T) { cip := &ClusterImagePolicy{Spec: ClusterImagePolicySpec{Images: []ImagePattern{{Glob: ""}}}} if err := cip.Validate(apis.WithinSubResourceUpdate(context.Background(), &cip, "status")); err != nil { t.Errorf("Failed to update status on invalid resource: %v", err) } } ================================================ FILE: pkg/apis/policy/v1beta1/doc.go ================================================ // 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. // +k8s:deepcopy-gen=package // +groupName=policy.sigstore.dev package v1beta1 ================================================ FILE: pkg/apis/policy/v1beta1/register.go ================================================ // 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. package v1beta1 import ( policy "github.com/sigstore/policy-controller/pkg/apis/policy" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" ) // SchemeGroupVersion is group version used to register these objects var SchemeGroupVersion = schema.GroupVersion{Group: policy.GroupName, Version: "v1beta1"} // Kind takes an unqualified kind and returns back a Group qualified GroupKind func Kind(kind string) schema.GroupKind { return SchemeGroupVersion.WithKind(kind).GroupKind() } // Resource takes an unqualified resource and returns a Group qualified GroupResource func Resource(resource string) schema.GroupResource { return SchemeGroupVersion.WithResource(resource).GroupResource() } var ( // SchemeBuilder builds a scheme with the types known to the package. SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) // AddToScheme adds the types known to this package to an existing schema. AddToScheme = SchemeBuilder.AddToScheme ) // Adds the list of known types to Scheme. func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &ClusterImagePolicy{}, &ClusterImagePolicyList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil } ================================================ FILE: pkg/apis/policy/v1beta1/zz_generated.deepcopy.go ================================================ //go:build !ignore_autogenerated // +build !ignore_autogenerated // 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. // Code generated by deepcopy-gen. DO NOT EDIT. package v1beta1 import ( v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" apis "knative.dev/pkg/apis" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Attestation) DeepCopyInto(out *Attestation) { *out = *in if in.Policy != nil { in, out := &in.Policy, &out.Policy *out = new(Policy) (*in).DeepCopyInto(*out) } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Attestation. func (in *Attestation) DeepCopy() *Attestation { if in == nil { return nil } out := new(Attestation) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Authority) DeepCopyInto(out *Authority) { *out = *in if in.Key != nil { in, out := &in.Key, &out.Key *out = new(KeyRef) (*in).DeepCopyInto(*out) } if in.Keyless != nil { in, out := &in.Keyless, &out.Keyless *out = new(KeylessRef) (*in).DeepCopyInto(*out) } if in.Static != nil { in, out := &in.Static, &out.Static *out = new(StaticRef) **out = **in } if in.Sources != nil { in, out := &in.Sources, &out.Sources *out = make([]Source, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } if in.CTLog != nil { in, out := &in.CTLog, &out.CTLog *out = new(TLog) (*in).DeepCopyInto(*out) } if in.Attestations != nil { in, out := &in.Attestations, &out.Attestations *out = make([]Attestation, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } if in.RFC3161Timestamp != nil { in, out := &in.RFC3161Timestamp, &out.RFC3161Timestamp *out = new(RFC3161Timestamp) **out = **in } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Authority. func (in *Authority) DeepCopy() *Authority { if in == nil { return nil } out := new(Authority) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterImagePolicy) DeepCopyInto(out *ClusterImagePolicy) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) in.Status.DeepCopyInto(&out.Status) return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterImagePolicy. func (in *ClusterImagePolicy) DeepCopy() *ClusterImagePolicy { if in == nil { return nil } out := new(ClusterImagePolicy) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. func (in *ClusterImagePolicy) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } return nil } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterImagePolicyList) DeepCopyInto(out *ClusterImagePolicyList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items *out = make([]ClusterImagePolicy, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterImagePolicyList. func (in *ClusterImagePolicyList) DeepCopy() *ClusterImagePolicyList { if in == nil { return nil } out := new(ClusterImagePolicyList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. func (in *ClusterImagePolicyList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } return nil } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterImagePolicySpec) DeepCopyInto(out *ClusterImagePolicySpec) { *out = *in if in.Images != nil { in, out := &in.Images, &out.Images *out = make([]ImagePattern, len(*in)) copy(*out, *in) } if in.Authorities != nil { in, out := &in.Authorities, &out.Authorities *out = make([]Authority, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } if in.Policy != nil { in, out := &in.Policy, &out.Policy *out = new(Policy) (*in).DeepCopyInto(*out) } if in.Match != nil { in, out := &in.Match, &out.Match *out = make([]MatchResource, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterImagePolicySpec. func (in *ClusterImagePolicySpec) DeepCopy() *ClusterImagePolicySpec { if in == nil { return nil } out := new(ClusterImagePolicySpec) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ClusterImagePolicyStatus) DeepCopyInto(out *ClusterImagePolicyStatus) { *out = *in in.Status.DeepCopyInto(&out.Status) return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterImagePolicyStatus. func (in *ClusterImagePolicyStatus) DeepCopy() *ClusterImagePolicyStatus { if in == nil { return nil } out := new(ClusterImagePolicyStatus) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ConfigMapReference) DeepCopyInto(out *ConfigMapReference) { *out = *in return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigMapReference. func (in *ConfigMapReference) DeepCopy() *ConfigMapReference { if in == nil { return nil } out := new(ConfigMapReference) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Identity) DeepCopyInto(out *Identity) { *out = *in return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Identity. func (in *Identity) DeepCopy() *Identity { if in == nil { return nil } out := new(Identity) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ImagePattern) DeepCopyInto(out *ImagePattern) { *out = *in return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImagePattern. func (in *ImagePattern) DeepCopy() *ImagePattern { if in == nil { return nil } out := new(ImagePattern) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KeyRef) DeepCopyInto(out *KeyRef) { *out = *in if in.SecretRef != nil { in, out := &in.SecretRef, &out.SecretRef *out = new(v1.SecretReference) **out = **in } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyRef. func (in *KeyRef) DeepCopy() *KeyRef { if in == nil { return nil } out := new(KeyRef) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *KeylessRef) DeepCopyInto(out *KeylessRef) { *out = *in if in.URL != nil { in, out := &in.URL, &out.URL *out = new(apis.URL) (*in).DeepCopyInto(*out) } if in.Identities != nil { in, out := &in.Identities, &out.Identities *out = make([]Identity, len(*in)) copy(*out, *in) } if in.CACert != nil { in, out := &in.CACert, &out.CACert *out = new(KeyRef) (*in).DeepCopyInto(*out) } if in.InsecureIgnoreSCT != nil { in, out := &in.InsecureIgnoreSCT, &out.InsecureIgnoreSCT *out = new(bool) **out = **in } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeylessRef. func (in *KeylessRef) DeepCopy() *KeylessRef { if in == nil { return nil } out := new(KeylessRef) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MatchResource) DeepCopyInto(out *MatchResource) { *out = *in out.GroupVersionResource = in.GroupVersionResource if in.ResourceSelector != nil { in, out := &in.ResourceSelector, &out.ResourceSelector *out = new(metav1.LabelSelector) (*in).DeepCopyInto(*out) } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MatchResource. func (in *MatchResource) DeepCopy() *MatchResource { if in == nil { return nil } out := new(MatchResource) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Policy) DeepCopyInto(out *Policy) { *out = *in if in.Remote != nil { in, out := &in.Remote, &out.Remote *out = new(RemotePolicy) (*in).DeepCopyInto(*out) } if in.ConfigMapRef != nil { in, out := &in.ConfigMapRef, &out.ConfigMapRef *out = new(ConfigMapReference) **out = **in } if in.FetchConfigFile != nil { in, out := &in.FetchConfigFile, &out.FetchConfigFile *out = new(bool) **out = **in } if in.IncludeSpec != nil { in, out := &in.IncludeSpec, &out.IncludeSpec *out = new(bool) **out = **in } if in.IncludeObjectMeta != nil { in, out := &in.IncludeObjectMeta, &out.IncludeObjectMeta *out = new(bool) **out = **in } if in.IncludeTypeMeta != nil { in, out := &in.IncludeTypeMeta, &out.IncludeTypeMeta *out = new(bool) **out = **in } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Policy. func (in *Policy) DeepCopy() *Policy { if in == nil { return nil } out := new(Policy) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RFC3161Timestamp) DeepCopyInto(out *RFC3161Timestamp) { *out = *in return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RFC3161Timestamp. func (in *RFC3161Timestamp) DeepCopy() *RFC3161Timestamp { if in == nil { return nil } out := new(RFC3161Timestamp) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RemotePolicy) DeepCopyInto(out *RemotePolicy) { *out = *in in.URL.DeepCopyInto(&out.URL) return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemotePolicy. func (in *RemotePolicy) DeepCopy() *RemotePolicy { if in == nil { return nil } out := new(RemotePolicy) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Source) DeepCopyInto(out *Source) { *out = *in if in.SignaturePullSecrets != nil { in, out := &in.SignaturePullSecrets, &out.SignaturePullSecrets *out = make([]v1.LocalObjectReference, len(*in)) copy(*out, *in) } if in.TagPrefix != nil { in, out := &in.TagPrefix, &out.TagPrefix *out = new(string) **out = **in } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Source. func (in *Source) DeepCopy() *Source { if in == nil { return nil } out := new(Source) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *StaticRef) DeepCopyInto(out *StaticRef) { *out = *in return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StaticRef. func (in *StaticRef) DeepCopy() *StaticRef { if in == nil { return nil } out := new(StaticRef) in.DeepCopyInto(out) return out } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TLog) DeepCopyInto(out *TLog) { *out = *in if in.URL != nil { in, out := &in.URL, &out.URL *out = new(apis.URL) (*in).DeepCopyInto(*out) } return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLog. func (in *TLog) DeepCopy() *TLog { if in == nil { return nil } out := new(TLog) in.DeepCopyInto(out) return out } ================================================ FILE: pkg/apis/signaturealgo/signature_digest.go ================================================ // // 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. package signaturealgo import ( "crypto" "fmt" "strings" ) var DefaultSignatureAlgorithm = "sha256" // supportedSignatureAlgorithms sets a list of support signature algorithms that is similar to the list supported by cosign var supportedSignatureAlgorithms = map[string]crypto.Hash{ "sha224": crypto.SHA224, "sha256": crypto.SHA256, "sha384": crypto.SHA384, "sha512": crypto.SHA512, } // HashAlgorithm returns a crypto.Hash code using an algorithm name as input parameter func HashAlgorithm(algorithmName string) (crypto.Hash, error) { if algorithmName == "" { return crypto.SHA256, nil } normalizedAlgo := strings.ToLower(strings.TrimSpace(algorithmName)) algo, exists := supportedSignatureAlgorithms[normalizedAlgo] if !exists { return crypto.SHA256, fmt.Errorf("unknown digest algorithm: %s", algorithmName) } return algo, nil } ================================================ FILE: pkg/apis/signaturealgo/signature_digest_test.go ================================================ // 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. package signaturealgo import ( "crypto" "testing" ) func TestHashAlgorithm(t *testing.T) { for _, c := range []struct { algorithm string wantHash crypto.Hash wantErr bool }{ {algorithm: "sha256", wantErr: false, wantHash: crypto.SHA256}, {algorithm: "sha512", wantErr: false, wantHash: crypto.SHA512}, {algorithm: "sha224", wantErr: false, wantHash: crypto.SHA224}, {algorithm: "sha384", wantErr: false, wantHash: crypto.SHA384}, {algorithm: "sha3845", wantErr: true, wantHash: crypto.SHA256}, {algorithm: "", wantErr: false, wantHash: crypto.SHA256}, } { t.Run(c.algorithm, func(t *testing.T) { hashCode, err := HashAlgorithm(c.algorithm) if hashCode != c.wantHash { t.Errorf("hash code: got %v, want %v", hashCode, c.wantHash) } if gotErr := err != nil; gotErr != c.wantErr { t.Errorf("err: got %v, want %t", err, c.wantErr) } }) } } ================================================ FILE: pkg/client/clientset/versioned/clientset.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. package versioned import ( "fmt" "net/http" policyv1alpha1 "github.com/sigstore/policy-controller/pkg/client/clientset/versioned/typed/policy/v1alpha1" policyv1beta1 "github.com/sigstore/policy-controller/pkg/client/clientset/versioned/typed/policy/v1beta1" discovery "k8s.io/client-go/discovery" rest "k8s.io/client-go/rest" flowcontrol "k8s.io/client-go/util/flowcontrol" ) type Interface interface { Discovery() discovery.DiscoveryInterface PolicyV1alpha1() policyv1alpha1.PolicyV1alpha1Interface PolicyV1beta1() policyv1beta1.PolicyV1beta1Interface } // Clientset contains the clients for groups. type Clientset struct { *discovery.DiscoveryClient policyV1alpha1 *policyv1alpha1.PolicyV1alpha1Client policyV1beta1 *policyv1beta1.PolicyV1beta1Client } // PolicyV1alpha1 retrieves the PolicyV1alpha1Client func (c *Clientset) PolicyV1alpha1() policyv1alpha1.PolicyV1alpha1Interface { return c.policyV1alpha1 } // PolicyV1beta1 retrieves the PolicyV1beta1Client func (c *Clientset) PolicyV1beta1() policyv1beta1.PolicyV1beta1Interface { return c.policyV1beta1 } // Discovery retrieves the DiscoveryClient func (c *Clientset) Discovery() discovery.DiscoveryInterface { if c == nil { return nil } return c.DiscoveryClient } // NewForConfig creates a new Clientset for the given config. // If config's RateLimiter is not set and QPS and Burst are acceptable, // NewForConfig will generate a rate-limiter in configShallowCopy. // NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), // where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*Clientset, error) { configShallowCopy := *c if configShallowCopy.UserAgent == "" { configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent() } // share the transport between all clients httpClient, err := rest.HTTPClientFor(&configShallowCopy) if err != nil { return nil, err } return NewForConfigAndClient(&configShallowCopy, httpClient) } // NewForConfigAndClient creates a new Clientset for the given config and http client. // Note the http client provided takes precedence over the configured transport values. // If config's RateLimiter is not set and QPS and Burst are acceptable, // NewForConfigAndClient will generate a rate-limiter in configShallowCopy. func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) { configShallowCopy := *c if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { if configShallowCopy.Burst <= 0 { return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") } configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) } var cs Clientset var err error cs.policyV1alpha1, err = policyv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient) if err != nil { return nil, err } cs.policyV1beta1, err = policyv1beta1.NewForConfigAndClient(&configShallowCopy, httpClient) if err != nil { return nil, err } cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient) if err != nil { return nil, err } return &cs, nil } // NewForConfigOrDie creates a new Clientset for the given config and // panics if there is an error in the config. func NewForConfigOrDie(c *rest.Config) *Clientset { cs, err := NewForConfig(c) if err != nil { panic(err) } return cs } // New creates a new Clientset for the given RESTClient. func New(c rest.Interface) *Clientset { var cs Clientset cs.policyV1alpha1 = policyv1alpha1.New(c) cs.policyV1beta1 = policyv1beta1.New(c) cs.DiscoveryClient = discovery.NewDiscoveryClient(c) return &cs } ================================================ FILE: pkg/client/clientset/versioned/doc.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. // This package has the automatically generated clientset. package versioned ================================================ FILE: pkg/client/clientset/versioned/fake/clientset_generated.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. package fake import ( clientset "github.com/sigstore/policy-controller/pkg/client/clientset/versioned" policyv1alpha1 "github.com/sigstore/policy-controller/pkg/client/clientset/versioned/typed/policy/v1alpha1" fakepolicyv1alpha1 "github.com/sigstore/policy-controller/pkg/client/clientset/versioned/typed/policy/v1alpha1/fake" policyv1beta1 "github.com/sigstore/policy-controller/pkg/client/clientset/versioned/typed/policy/v1beta1" fakepolicyv1beta1 "github.com/sigstore/policy-controller/pkg/client/clientset/versioned/typed/policy/v1beta1/fake" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/discovery" fakediscovery "k8s.io/client-go/discovery/fake" "k8s.io/client-go/testing" ) // NewSimpleClientset returns a clientset that will respond with the provided objects. // It's backed by a very simple object tracker that processes creates, updates and deletions as-is, // without applying any validations and/or defaults. It shouldn't be considered a replacement // for a real clientset and is mostly useful in simple unit tests. func NewSimpleClientset(objects ...runtime.Object) *Clientset { o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) for _, obj := range objects { if err := o.Add(obj); err != nil { panic(err) } } cs := &Clientset{tracker: o} cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} cs.AddReactor("*", "*", testing.ObjectReaction(o)) cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { gvr := action.GetResource() ns := action.GetNamespace() watch, err := o.Watch(gvr, ns) if err != nil { return false, nil, err } return true, watch, nil }) return cs } // Clientset implements clientset.Interface. Meant to be embedded into a // struct to get a default implementation. This makes faking out just the method // you want to test easier. type Clientset struct { testing.Fake discovery *fakediscovery.FakeDiscovery tracker testing.ObjectTracker } func (c *Clientset) Discovery() discovery.DiscoveryInterface { return c.discovery } func (c *Clientset) Tracker() testing.ObjectTracker { return c.tracker } var ( _ clientset.Interface = &Clientset{} _ testing.FakeClient = &Clientset{} ) // PolicyV1alpha1 retrieves the PolicyV1alpha1Client func (c *Clientset) PolicyV1alpha1() policyv1alpha1.PolicyV1alpha1Interface { return &fakepolicyv1alpha1.FakePolicyV1alpha1{Fake: &c.Fake} } // PolicyV1beta1 retrieves the PolicyV1beta1Client func (c *Clientset) PolicyV1beta1() policyv1beta1.PolicyV1beta1Interface { return &fakepolicyv1beta1.FakePolicyV1beta1{Fake: &c.Fake} } ================================================ FILE: pkg/client/clientset/versioned/fake/doc.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. // This package has the automatically generated fake clientset. package fake ================================================ FILE: pkg/client/clientset/versioned/fake/register.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. package fake import ( policyv1alpha1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" policyv1beta1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1beta1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" serializer "k8s.io/apimachinery/pkg/runtime/serializer" utilruntime "k8s.io/apimachinery/pkg/util/runtime" ) var scheme = runtime.NewScheme() var codecs = serializer.NewCodecFactory(scheme) var localSchemeBuilder = runtime.SchemeBuilder{ policyv1alpha1.AddToScheme, policyv1beta1.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition // of clientsets, like in: // // import ( // "k8s.io/client-go/kubernetes" // clientsetscheme "k8s.io/client-go/kubernetes/scheme" // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" // ) // // kclientset, _ := kubernetes.NewForConfig(c) // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) // // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. var AddToScheme = localSchemeBuilder.AddToScheme func init() { v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) utilruntime.Must(AddToScheme(scheme)) } ================================================ FILE: pkg/client/clientset/versioned/scheme/doc.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. // This package contains the scheme of the automatically generated clientset. package scheme ================================================ FILE: pkg/client/clientset/versioned/scheme/register.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. package scheme import ( policyv1alpha1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" policyv1beta1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1beta1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" serializer "k8s.io/apimachinery/pkg/runtime/serializer" utilruntime "k8s.io/apimachinery/pkg/util/runtime" ) var Scheme = runtime.NewScheme() var Codecs = serializer.NewCodecFactory(Scheme) var ParameterCodec = runtime.NewParameterCodec(Scheme) var localSchemeBuilder = runtime.SchemeBuilder{ policyv1alpha1.AddToScheme, policyv1beta1.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition // of clientsets, like in: // // import ( // "k8s.io/client-go/kubernetes" // clientsetscheme "k8s.io/client-go/kubernetes/scheme" // aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" // ) // // kclientset, _ := kubernetes.NewForConfig(c) // _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) // // After this, RawExtensions in Kubernetes types will serialize kube-aggregator types // correctly. var AddToScheme = localSchemeBuilder.AddToScheme func init() { v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) utilruntime.Must(AddToScheme(Scheme)) } ================================================ FILE: pkg/client/clientset/versioned/typed/duck/v1beta1/doc.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. // This package has the automatically generated typed clients. package v1beta1 ================================================ FILE: pkg/client/clientset/versioned/typed/duck/v1beta1/duck_client.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. package v1beta1 import ( "net/http" v1beta1 "github.com/sigstore/policy-controller/pkg/apis/duck/v1beta1" "github.com/sigstore/policy-controller/pkg/client/clientset/versioned/scheme" rest "k8s.io/client-go/rest" ) type DuckV1beta1Interface interface { RESTClient() rest.Interface } // DuckV1beta1Client is used to interact with features provided by the duck.sigstore.policy.dev group. type DuckV1beta1Client struct { restClient rest.Interface } // NewForConfig creates a new DuckV1beta1Client for the given config. // NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), // where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*DuckV1beta1Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err } httpClient, err := rest.HTTPClientFor(&config) if err != nil { return nil, err } return NewForConfigAndClient(&config, httpClient) } // NewForConfigAndClient creates a new DuckV1beta1Client for the given config and http client. // Note the http client provided takes precedence over the configured transport values. func NewForConfigAndClient(c *rest.Config, h *http.Client) (*DuckV1beta1Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err } client, err := rest.RESTClientForConfigAndClient(&config, h) if err != nil { return nil, err } return &DuckV1beta1Client{client}, nil } // NewForConfigOrDie creates a new DuckV1beta1Client for the given config and // panics if there is an error in the config. func NewForConfigOrDie(c *rest.Config) *DuckV1beta1Client { client, err := NewForConfig(c) if err != nil { panic(err) } return client } // New creates a new DuckV1beta1Client for the given RESTClient. func New(c rest.Interface) *DuckV1beta1Client { return &DuckV1beta1Client{c} } func setConfigDefaults(config *rest.Config) error { gv := v1beta1.SchemeGroupVersion config.GroupVersion = &gv config.APIPath = "/apis" config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() if config.UserAgent == "" { config.UserAgent = rest.DefaultKubernetesUserAgent() } return nil } // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. func (c *DuckV1beta1Client) RESTClient() rest.Interface { if c == nil { return nil } return c.restClient } ================================================ FILE: pkg/client/clientset/versioned/typed/duck/v1beta1/fake/doc.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. // Package fake has the automatically generated clients. package fake ================================================ FILE: pkg/client/clientset/versioned/typed/duck/v1beta1/fake/fake_duck_client.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. package fake import ( rest "k8s.io/client-go/rest" testing "k8s.io/client-go/testing" ) type FakeDuckV1beta1 struct { *testing.Fake } // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. func (c *FakeDuckV1beta1) RESTClient() rest.Interface { var ret *rest.RESTClient return ret } ================================================ FILE: pkg/client/clientset/versioned/typed/duck/v1beta1/generated_expansion.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. package v1beta1 ================================================ FILE: pkg/client/clientset/versioned/typed/policy/v1alpha1/clusterimagepolicy.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. package v1alpha1 import ( "context" "time" v1alpha1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" scheme "github.com/sigstore/policy-controller/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" rest "k8s.io/client-go/rest" ) // ClusterImagePoliciesGetter has a method to return a ClusterImagePolicyInterface. // A group's client should implement this interface. type ClusterImagePoliciesGetter interface { ClusterImagePolicies() ClusterImagePolicyInterface } // ClusterImagePolicyInterface has methods to work with ClusterImagePolicy resources. type ClusterImagePolicyInterface interface { Create(ctx context.Context, clusterImagePolicy *v1alpha1.ClusterImagePolicy, opts v1.CreateOptions) (*v1alpha1.ClusterImagePolicy, error) Update(ctx context.Context, clusterImagePolicy *v1alpha1.ClusterImagePolicy, opts v1.UpdateOptions) (*v1alpha1.ClusterImagePolicy, error) UpdateStatus(ctx context.Context, clusterImagePolicy *v1alpha1.ClusterImagePolicy, opts v1.UpdateOptions) (*v1alpha1.ClusterImagePolicy, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.ClusterImagePolicy, error) List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.ClusterImagePolicyList, error) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ClusterImagePolicy, err error) ClusterImagePolicyExpansion } // clusterImagePolicies implements ClusterImagePolicyInterface type clusterImagePolicies struct { client rest.Interface } // newClusterImagePolicies returns a ClusterImagePolicies func newClusterImagePolicies(c *PolicyV1alpha1Client) *clusterImagePolicies { return &clusterImagePolicies{ client: c.RESTClient(), } } // Get takes name of the clusterImagePolicy, and returns the corresponding clusterImagePolicy object, and an error if there is any. func (c *clusterImagePolicies) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ClusterImagePolicy, err error) { result = &v1alpha1.ClusterImagePolicy{} err = c.client.Get(). Resource("clusterimagepolicies"). Name(name). VersionedParams(&options, scheme.ParameterCodec). Do(ctx). Into(result) return } // List takes label and field selectors, and returns the list of ClusterImagePolicies that match those selectors. func (c *clusterImagePolicies) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ClusterImagePolicyList, err error) { var timeout time.Duration if opts.TimeoutSeconds != nil { timeout = time.Duration(*opts.TimeoutSeconds) * time.Second } result = &v1alpha1.ClusterImagePolicyList{} err = c.client.Get(). Resource("clusterimagepolicies"). VersionedParams(&opts, scheme.ParameterCodec). Timeout(timeout). Do(ctx). Into(result) return } // Watch returns a watch.Interface that watches the requested clusterImagePolicies. func (c *clusterImagePolicies) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { var timeout time.Duration if opts.TimeoutSeconds != nil { timeout = time.Duration(*opts.TimeoutSeconds) * time.Second } opts.Watch = true return c.client.Get(). Resource("clusterimagepolicies"). VersionedParams(&opts, scheme.ParameterCodec). Timeout(timeout). Watch(ctx) } // Create takes the representation of a clusterImagePolicy and creates it. Returns the server's representation of the clusterImagePolicy, and an error, if there is any. func (c *clusterImagePolicies) Create(ctx context.Context, clusterImagePolicy *v1alpha1.ClusterImagePolicy, opts v1.CreateOptions) (result *v1alpha1.ClusterImagePolicy, err error) { result = &v1alpha1.ClusterImagePolicy{} err = c.client.Post(). Resource("clusterimagepolicies"). VersionedParams(&opts, scheme.ParameterCodec). Body(clusterImagePolicy). Do(ctx). Into(result) return } // Update takes the representation of a clusterImagePolicy and updates it. Returns the server's representation of the clusterImagePolicy, and an error, if there is any. func (c *clusterImagePolicies) Update(ctx context.Context, clusterImagePolicy *v1alpha1.ClusterImagePolicy, opts v1.UpdateOptions) (result *v1alpha1.ClusterImagePolicy, err error) { result = &v1alpha1.ClusterImagePolicy{} err = c.client.Put(). Resource("clusterimagepolicies"). Name(clusterImagePolicy.Name). VersionedParams(&opts, scheme.ParameterCodec). Body(clusterImagePolicy). Do(ctx). Into(result) return } // UpdateStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). func (c *clusterImagePolicies) UpdateStatus(ctx context.Context, clusterImagePolicy *v1alpha1.ClusterImagePolicy, opts v1.UpdateOptions) (result *v1alpha1.ClusterImagePolicy, err error) { result = &v1alpha1.ClusterImagePolicy{} err = c.client.Put(). Resource("clusterimagepolicies"). Name(clusterImagePolicy.Name). SubResource("status"). VersionedParams(&opts, scheme.ParameterCodec). Body(clusterImagePolicy). Do(ctx). Into(result) return } // Delete takes name of the clusterImagePolicy and deletes it. Returns an error if one occurs. func (c *clusterImagePolicies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { return c.client.Delete(). Resource("clusterimagepolicies"). Name(name). Body(&opts). Do(ctx). Error() } // DeleteCollection deletes a collection of objects. func (c *clusterImagePolicies) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { var timeout time.Duration if listOpts.TimeoutSeconds != nil { timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second } return c.client.Delete(). Resource("clusterimagepolicies"). VersionedParams(&listOpts, scheme.ParameterCodec). Timeout(timeout). Body(&opts). Do(ctx). Error() } // Patch applies the patch and returns the patched clusterImagePolicy. func (c *clusterImagePolicies) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ClusterImagePolicy, err error) { result = &v1alpha1.ClusterImagePolicy{} err = c.client.Patch(pt). Resource("clusterimagepolicies"). Name(name). SubResource(subresources...). VersionedParams(&opts, scheme.ParameterCodec). Body(data). Do(ctx). Into(result) return } ================================================ FILE: pkg/client/clientset/versioned/typed/policy/v1alpha1/doc.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. // This package has the automatically generated typed clients. package v1alpha1 ================================================ FILE: pkg/client/clientset/versioned/typed/policy/v1alpha1/fake/doc.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. // Package fake has the automatically generated clients. package fake ================================================ FILE: pkg/client/clientset/versioned/typed/policy/v1alpha1/fake/fake_clusterimagepolicy.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. package fake import ( "context" v1alpha1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" labels "k8s.io/apimachinery/pkg/labels" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" testing "k8s.io/client-go/testing" ) // FakeClusterImagePolicies implements ClusterImagePolicyInterface type FakeClusterImagePolicies struct { Fake *FakePolicyV1alpha1 } var clusterimagepoliciesResource = v1alpha1.SchemeGroupVersion.WithResource("clusterimagepolicies") var clusterimagepoliciesKind = v1alpha1.SchemeGroupVersion.WithKind("ClusterImagePolicy") // Get takes name of the clusterImagePolicy, and returns the corresponding clusterImagePolicy object, and an error if there is any. func (c *FakeClusterImagePolicies) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ClusterImagePolicy, err error) { obj, err := c.Fake. Invokes(testing.NewRootGetAction(clusterimagepoliciesResource, name), &v1alpha1.ClusterImagePolicy{}) if obj == nil { return nil, err } return obj.(*v1alpha1.ClusterImagePolicy), err } // List takes label and field selectors, and returns the list of ClusterImagePolicies that match those selectors. func (c *FakeClusterImagePolicies) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ClusterImagePolicyList, err error) { obj, err := c.Fake. Invokes(testing.NewRootListAction(clusterimagepoliciesResource, clusterimagepoliciesKind, opts), &v1alpha1.ClusterImagePolicyList{}) if obj == nil { return nil, err } label, _, _ := testing.ExtractFromListOptions(opts) if label == nil { label = labels.Everything() } list := &v1alpha1.ClusterImagePolicyList{ListMeta: obj.(*v1alpha1.ClusterImagePolicyList).ListMeta} for _, item := range obj.(*v1alpha1.ClusterImagePolicyList).Items { if label.Matches(labels.Set(item.Labels)) { list.Items = append(list.Items, item) } } return list, err } // Watch returns a watch.Interface that watches the requested clusterImagePolicies. func (c *FakeClusterImagePolicies) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. InvokesWatch(testing.NewRootWatchAction(clusterimagepoliciesResource, opts)) } // Create takes the representation of a clusterImagePolicy and creates it. Returns the server's representation of the clusterImagePolicy, and an error, if there is any. func (c *FakeClusterImagePolicies) Create(ctx context.Context, clusterImagePolicy *v1alpha1.ClusterImagePolicy, opts v1.CreateOptions) (result *v1alpha1.ClusterImagePolicy, err error) { obj, err := c.Fake. Invokes(testing.NewRootCreateAction(clusterimagepoliciesResource, clusterImagePolicy), &v1alpha1.ClusterImagePolicy{}) if obj == nil { return nil, err } return obj.(*v1alpha1.ClusterImagePolicy), err } // Update takes the representation of a clusterImagePolicy and updates it. Returns the server's representation of the clusterImagePolicy, and an error, if there is any. func (c *FakeClusterImagePolicies) Update(ctx context.Context, clusterImagePolicy *v1alpha1.ClusterImagePolicy, opts v1.UpdateOptions) (result *v1alpha1.ClusterImagePolicy, err error) { obj, err := c.Fake. Invokes(testing.NewRootUpdateAction(clusterimagepoliciesResource, clusterImagePolicy), &v1alpha1.ClusterImagePolicy{}) if obj == nil { return nil, err } return obj.(*v1alpha1.ClusterImagePolicy), err } // UpdateStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). func (c *FakeClusterImagePolicies) UpdateStatus(ctx context.Context, clusterImagePolicy *v1alpha1.ClusterImagePolicy, opts v1.UpdateOptions) (*v1alpha1.ClusterImagePolicy, error) { obj, err := c.Fake. Invokes(testing.NewRootUpdateSubresourceAction(clusterimagepoliciesResource, "status", clusterImagePolicy), &v1alpha1.ClusterImagePolicy{}) if obj == nil { return nil, err } return obj.(*v1alpha1.ClusterImagePolicy), err } // Delete takes name of the clusterImagePolicy and deletes it. Returns an error if one occurs. func (c *FakeClusterImagePolicies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. Invokes(testing.NewRootDeleteActionWithOptions(clusterimagepoliciesResource, name, opts), &v1alpha1.ClusterImagePolicy{}) return err } // DeleteCollection deletes a collection of objects. func (c *FakeClusterImagePolicies) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { action := testing.NewRootDeleteCollectionAction(clusterimagepoliciesResource, listOpts) _, err := c.Fake.Invokes(action, &v1alpha1.ClusterImagePolicyList{}) return err } // Patch applies the patch and returns the patched clusterImagePolicy. func (c *FakeClusterImagePolicies) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ClusterImagePolicy, err error) { obj, err := c.Fake. Invokes(testing.NewRootPatchSubresourceAction(clusterimagepoliciesResource, name, pt, data, subresources...), &v1alpha1.ClusterImagePolicy{}) if obj == nil { return nil, err } return obj.(*v1alpha1.ClusterImagePolicy), err } ================================================ FILE: pkg/client/clientset/versioned/typed/policy/v1alpha1/fake/fake_policy_client.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. package fake import ( v1alpha1 "github.com/sigstore/policy-controller/pkg/client/clientset/versioned/typed/policy/v1alpha1" rest "k8s.io/client-go/rest" testing "k8s.io/client-go/testing" ) type FakePolicyV1alpha1 struct { *testing.Fake } func (c *FakePolicyV1alpha1) ClusterImagePolicies() v1alpha1.ClusterImagePolicyInterface { return &FakeClusterImagePolicies{c} } func (c *FakePolicyV1alpha1) TrustRoots() v1alpha1.TrustRootInterface { return &FakeTrustRoots{c} } // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. func (c *FakePolicyV1alpha1) RESTClient() rest.Interface { var ret *rest.RESTClient return ret } ================================================ FILE: pkg/client/clientset/versioned/typed/policy/v1alpha1/fake/fake_trustroot.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. package fake import ( "context" v1alpha1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" labels "k8s.io/apimachinery/pkg/labels" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" testing "k8s.io/client-go/testing" ) // FakeTrustRoots implements TrustRootInterface type FakeTrustRoots struct { Fake *FakePolicyV1alpha1 } var trustrootsResource = v1alpha1.SchemeGroupVersion.WithResource("trustroots") var trustrootsKind = v1alpha1.SchemeGroupVersion.WithKind("TrustRoot") // Get takes name of the trustRoot, and returns the corresponding trustRoot object, and an error if there is any. func (c *FakeTrustRoots) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.TrustRoot, err error) { obj, err := c.Fake. Invokes(testing.NewRootGetAction(trustrootsResource, name), &v1alpha1.TrustRoot{}) if obj == nil { return nil, err } return obj.(*v1alpha1.TrustRoot), err } // List takes label and field selectors, and returns the list of TrustRoots that match those selectors. func (c *FakeTrustRoots) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.TrustRootList, err error) { obj, err := c.Fake. Invokes(testing.NewRootListAction(trustrootsResource, trustrootsKind, opts), &v1alpha1.TrustRootList{}) if obj == nil { return nil, err } label, _, _ := testing.ExtractFromListOptions(opts) if label == nil { label = labels.Everything() } list := &v1alpha1.TrustRootList{ListMeta: obj.(*v1alpha1.TrustRootList).ListMeta} for _, item := range obj.(*v1alpha1.TrustRootList).Items { if label.Matches(labels.Set(item.Labels)) { list.Items = append(list.Items, item) } } return list, err } // Watch returns a watch.Interface that watches the requested trustRoots. func (c *FakeTrustRoots) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. InvokesWatch(testing.NewRootWatchAction(trustrootsResource, opts)) } // Create takes the representation of a trustRoot and creates it. Returns the server's representation of the trustRoot, and an error, if there is any. func (c *FakeTrustRoots) Create(ctx context.Context, trustRoot *v1alpha1.TrustRoot, opts v1.CreateOptions) (result *v1alpha1.TrustRoot, err error) { obj, err := c.Fake. Invokes(testing.NewRootCreateAction(trustrootsResource, trustRoot), &v1alpha1.TrustRoot{}) if obj == nil { return nil, err } return obj.(*v1alpha1.TrustRoot), err } // Update takes the representation of a trustRoot and updates it. Returns the server's representation of the trustRoot, and an error, if there is any. func (c *FakeTrustRoots) Update(ctx context.Context, trustRoot *v1alpha1.TrustRoot, opts v1.UpdateOptions) (result *v1alpha1.TrustRoot, err error) { obj, err := c.Fake. Invokes(testing.NewRootUpdateAction(trustrootsResource, trustRoot), &v1alpha1.TrustRoot{}) if obj == nil { return nil, err } return obj.(*v1alpha1.TrustRoot), err } // UpdateStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). func (c *FakeTrustRoots) UpdateStatus(ctx context.Context, trustRoot *v1alpha1.TrustRoot, opts v1.UpdateOptions) (*v1alpha1.TrustRoot, error) { obj, err := c.Fake. Invokes(testing.NewRootUpdateSubresourceAction(trustrootsResource, "status", trustRoot), &v1alpha1.TrustRoot{}) if obj == nil { return nil, err } return obj.(*v1alpha1.TrustRoot), err } // Delete takes name of the trustRoot and deletes it. Returns an error if one occurs. func (c *FakeTrustRoots) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. Invokes(testing.NewRootDeleteActionWithOptions(trustrootsResource, name, opts), &v1alpha1.TrustRoot{}) return err } // DeleteCollection deletes a collection of objects. func (c *FakeTrustRoots) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { action := testing.NewRootDeleteCollectionAction(trustrootsResource, listOpts) _, err := c.Fake.Invokes(action, &v1alpha1.TrustRootList{}) return err } // Patch applies the patch and returns the patched trustRoot. func (c *FakeTrustRoots) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.TrustRoot, err error) { obj, err := c.Fake. Invokes(testing.NewRootPatchSubresourceAction(trustrootsResource, name, pt, data, subresources...), &v1alpha1.TrustRoot{}) if obj == nil { return nil, err } return obj.(*v1alpha1.TrustRoot), err } ================================================ FILE: pkg/client/clientset/versioned/typed/policy/v1alpha1/generated_expansion.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. package v1alpha1 type ClusterImagePolicyExpansion interface{} type TrustRootExpansion interface{} ================================================ FILE: pkg/client/clientset/versioned/typed/policy/v1alpha1/policy_client.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. package v1alpha1 import ( "net/http" v1alpha1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" "github.com/sigstore/policy-controller/pkg/client/clientset/versioned/scheme" rest "k8s.io/client-go/rest" ) type PolicyV1alpha1Interface interface { RESTClient() rest.Interface ClusterImagePoliciesGetter TrustRootsGetter } // PolicyV1alpha1Client is used to interact with features provided by the policy.sigstore.dev group. type PolicyV1alpha1Client struct { restClient rest.Interface } func (c *PolicyV1alpha1Client) ClusterImagePolicies() ClusterImagePolicyInterface { return newClusterImagePolicies(c) } func (c *PolicyV1alpha1Client) TrustRoots() TrustRootInterface { return newTrustRoots(c) } // NewForConfig creates a new PolicyV1alpha1Client for the given config. // NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), // where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*PolicyV1alpha1Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err } httpClient, err := rest.HTTPClientFor(&config) if err != nil { return nil, err } return NewForConfigAndClient(&config, httpClient) } // NewForConfigAndClient creates a new PolicyV1alpha1Client for the given config and http client. // Note the http client provided takes precedence over the configured transport values. func NewForConfigAndClient(c *rest.Config, h *http.Client) (*PolicyV1alpha1Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err } client, err := rest.RESTClientForConfigAndClient(&config, h) if err != nil { return nil, err } return &PolicyV1alpha1Client{client}, nil } // NewForConfigOrDie creates a new PolicyV1alpha1Client for the given config and // panics if there is an error in the config. func NewForConfigOrDie(c *rest.Config) *PolicyV1alpha1Client { client, err := NewForConfig(c) if err != nil { panic(err) } return client } // New creates a new PolicyV1alpha1Client for the given RESTClient. func New(c rest.Interface) *PolicyV1alpha1Client { return &PolicyV1alpha1Client{c} } func setConfigDefaults(config *rest.Config) error { gv := v1alpha1.SchemeGroupVersion config.GroupVersion = &gv config.APIPath = "/apis" config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() if config.UserAgent == "" { config.UserAgent = rest.DefaultKubernetesUserAgent() } return nil } // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. func (c *PolicyV1alpha1Client) RESTClient() rest.Interface { if c == nil { return nil } return c.restClient } ================================================ FILE: pkg/client/clientset/versioned/typed/policy/v1alpha1/trustroot.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. package v1alpha1 import ( "context" "time" v1alpha1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" scheme "github.com/sigstore/policy-controller/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" rest "k8s.io/client-go/rest" ) // TrustRootsGetter has a method to return a TrustRootInterface. // A group's client should implement this interface. type TrustRootsGetter interface { TrustRoots() TrustRootInterface } // TrustRootInterface has methods to work with TrustRoot resources. type TrustRootInterface interface { Create(ctx context.Context, trustRoot *v1alpha1.TrustRoot, opts v1.CreateOptions) (*v1alpha1.TrustRoot, error) Update(ctx context.Context, trustRoot *v1alpha1.TrustRoot, opts v1.UpdateOptions) (*v1alpha1.TrustRoot, error) UpdateStatus(ctx context.Context, trustRoot *v1alpha1.TrustRoot, opts v1.UpdateOptions) (*v1alpha1.TrustRoot, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.TrustRoot, error) List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.TrustRootList, error) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.TrustRoot, err error) TrustRootExpansion } // trustRoots implements TrustRootInterface type trustRoots struct { client rest.Interface } // newTrustRoots returns a TrustRoots func newTrustRoots(c *PolicyV1alpha1Client) *trustRoots { return &trustRoots{ client: c.RESTClient(), } } // Get takes name of the trustRoot, and returns the corresponding trustRoot object, and an error if there is any. func (c *trustRoots) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.TrustRoot, err error) { result = &v1alpha1.TrustRoot{} err = c.client.Get(). Resource("trustroots"). Name(name). VersionedParams(&options, scheme.ParameterCodec). Do(ctx). Into(result) return } // List takes label and field selectors, and returns the list of TrustRoots that match those selectors. func (c *trustRoots) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.TrustRootList, err error) { var timeout time.Duration if opts.TimeoutSeconds != nil { timeout = time.Duration(*opts.TimeoutSeconds) * time.Second } result = &v1alpha1.TrustRootList{} err = c.client.Get(). Resource("trustroots"). VersionedParams(&opts, scheme.ParameterCodec). Timeout(timeout). Do(ctx). Into(result) return } // Watch returns a watch.Interface that watches the requested trustRoots. func (c *trustRoots) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { var timeout time.Duration if opts.TimeoutSeconds != nil { timeout = time.Duration(*opts.TimeoutSeconds) * time.Second } opts.Watch = true return c.client.Get(). Resource("trustroots"). VersionedParams(&opts, scheme.ParameterCodec). Timeout(timeout). Watch(ctx) } // Create takes the representation of a trustRoot and creates it. Returns the server's representation of the trustRoot, and an error, if there is any. func (c *trustRoots) Create(ctx context.Context, trustRoot *v1alpha1.TrustRoot, opts v1.CreateOptions) (result *v1alpha1.TrustRoot, err error) { result = &v1alpha1.TrustRoot{} err = c.client.Post(). Resource("trustroots"). VersionedParams(&opts, scheme.ParameterCodec). Body(trustRoot). Do(ctx). Into(result) return } // Update takes the representation of a trustRoot and updates it. Returns the server's representation of the trustRoot, and an error, if there is any. func (c *trustRoots) Update(ctx context.Context, trustRoot *v1alpha1.TrustRoot, opts v1.UpdateOptions) (result *v1alpha1.TrustRoot, err error) { result = &v1alpha1.TrustRoot{} err = c.client.Put(). Resource("trustroots"). Name(trustRoot.Name). VersionedParams(&opts, scheme.ParameterCodec). Body(trustRoot). Do(ctx). Into(result) return } // UpdateStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). func (c *trustRoots) UpdateStatus(ctx context.Context, trustRoot *v1alpha1.TrustRoot, opts v1.UpdateOptions) (result *v1alpha1.TrustRoot, err error) { result = &v1alpha1.TrustRoot{} err = c.client.Put(). Resource("trustroots"). Name(trustRoot.Name). SubResource("status"). VersionedParams(&opts, scheme.ParameterCodec). Body(trustRoot). Do(ctx). Into(result) return } // Delete takes name of the trustRoot and deletes it. Returns an error if one occurs. func (c *trustRoots) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { return c.client.Delete(). Resource("trustroots"). Name(name). Body(&opts). Do(ctx). Error() } // DeleteCollection deletes a collection of objects. func (c *trustRoots) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { var timeout time.Duration if listOpts.TimeoutSeconds != nil { timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second } return c.client.Delete(). Resource("trustroots"). VersionedParams(&listOpts, scheme.ParameterCodec). Timeout(timeout). Body(&opts). Do(ctx). Error() } // Patch applies the patch and returns the patched trustRoot. func (c *trustRoots) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.TrustRoot, err error) { result = &v1alpha1.TrustRoot{} err = c.client.Patch(pt). Resource("trustroots"). Name(name). SubResource(subresources...). VersionedParams(&opts, scheme.ParameterCodec). Body(data). Do(ctx). Into(result) return } ================================================ FILE: pkg/client/clientset/versioned/typed/policy/v1beta1/clusterimagepolicy.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. package v1beta1 import ( "context" "time" v1beta1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1beta1" scheme "github.com/sigstore/policy-controller/pkg/client/clientset/versioned/scheme" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" rest "k8s.io/client-go/rest" ) // ClusterImagePoliciesGetter has a method to return a ClusterImagePolicyInterface. // A group's client should implement this interface. type ClusterImagePoliciesGetter interface { ClusterImagePolicies() ClusterImagePolicyInterface } // ClusterImagePolicyInterface has methods to work with ClusterImagePolicy resources. type ClusterImagePolicyInterface interface { Create(ctx context.Context, clusterImagePolicy *v1beta1.ClusterImagePolicy, opts v1.CreateOptions) (*v1beta1.ClusterImagePolicy, error) Update(ctx context.Context, clusterImagePolicy *v1beta1.ClusterImagePolicy, opts v1.UpdateOptions) (*v1beta1.ClusterImagePolicy, error) UpdateStatus(ctx context.Context, clusterImagePolicy *v1beta1.ClusterImagePolicy, opts v1.UpdateOptions) (*v1beta1.ClusterImagePolicy, error) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error Get(ctx context.Context, name string, opts v1.GetOptions) (*v1beta1.ClusterImagePolicy, error) List(ctx context.Context, opts v1.ListOptions) (*v1beta1.ClusterImagePolicyList, error) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.ClusterImagePolicy, err error) ClusterImagePolicyExpansion } // clusterImagePolicies implements ClusterImagePolicyInterface type clusterImagePolicies struct { client rest.Interface } // newClusterImagePolicies returns a ClusterImagePolicies func newClusterImagePolicies(c *PolicyV1beta1Client) *clusterImagePolicies { return &clusterImagePolicies{ client: c.RESTClient(), } } // Get takes name of the clusterImagePolicy, and returns the corresponding clusterImagePolicy object, and an error if there is any. func (c *clusterImagePolicies) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.ClusterImagePolicy, err error) { result = &v1beta1.ClusterImagePolicy{} err = c.client.Get(). Resource("clusterimagepolicies"). Name(name). VersionedParams(&options, scheme.ParameterCodec). Do(ctx). Into(result) return } // List takes label and field selectors, and returns the list of ClusterImagePolicies that match those selectors. func (c *clusterImagePolicies) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.ClusterImagePolicyList, err error) { var timeout time.Duration if opts.TimeoutSeconds != nil { timeout = time.Duration(*opts.TimeoutSeconds) * time.Second } result = &v1beta1.ClusterImagePolicyList{} err = c.client.Get(). Resource("clusterimagepolicies"). VersionedParams(&opts, scheme.ParameterCodec). Timeout(timeout). Do(ctx). Into(result) return } // Watch returns a watch.Interface that watches the requested clusterImagePolicies. func (c *clusterImagePolicies) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { var timeout time.Duration if opts.TimeoutSeconds != nil { timeout = time.Duration(*opts.TimeoutSeconds) * time.Second } opts.Watch = true return c.client.Get(). Resource("clusterimagepolicies"). VersionedParams(&opts, scheme.ParameterCodec). Timeout(timeout). Watch(ctx) } // Create takes the representation of a clusterImagePolicy and creates it. Returns the server's representation of the clusterImagePolicy, and an error, if there is any. func (c *clusterImagePolicies) Create(ctx context.Context, clusterImagePolicy *v1beta1.ClusterImagePolicy, opts v1.CreateOptions) (result *v1beta1.ClusterImagePolicy, err error) { result = &v1beta1.ClusterImagePolicy{} err = c.client.Post(). Resource("clusterimagepolicies"). VersionedParams(&opts, scheme.ParameterCodec). Body(clusterImagePolicy). Do(ctx). Into(result) return } // Update takes the representation of a clusterImagePolicy and updates it. Returns the server's representation of the clusterImagePolicy, and an error, if there is any. func (c *clusterImagePolicies) Update(ctx context.Context, clusterImagePolicy *v1beta1.ClusterImagePolicy, opts v1.UpdateOptions) (result *v1beta1.ClusterImagePolicy, err error) { result = &v1beta1.ClusterImagePolicy{} err = c.client.Put(). Resource("clusterimagepolicies"). Name(clusterImagePolicy.Name). VersionedParams(&opts, scheme.ParameterCodec). Body(clusterImagePolicy). Do(ctx). Into(result) return } // UpdateStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). func (c *clusterImagePolicies) UpdateStatus(ctx context.Context, clusterImagePolicy *v1beta1.ClusterImagePolicy, opts v1.UpdateOptions) (result *v1beta1.ClusterImagePolicy, err error) { result = &v1beta1.ClusterImagePolicy{} err = c.client.Put(). Resource("clusterimagepolicies"). Name(clusterImagePolicy.Name). SubResource("status"). VersionedParams(&opts, scheme.ParameterCodec). Body(clusterImagePolicy). Do(ctx). Into(result) return } // Delete takes name of the clusterImagePolicy and deletes it. Returns an error if one occurs. func (c *clusterImagePolicies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { return c.client.Delete(). Resource("clusterimagepolicies"). Name(name). Body(&opts). Do(ctx). Error() } // DeleteCollection deletes a collection of objects. func (c *clusterImagePolicies) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { var timeout time.Duration if listOpts.TimeoutSeconds != nil { timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second } return c.client.Delete(). Resource("clusterimagepolicies"). VersionedParams(&listOpts, scheme.ParameterCodec). Timeout(timeout). Body(&opts). Do(ctx). Error() } // Patch applies the patch and returns the patched clusterImagePolicy. func (c *clusterImagePolicies) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.ClusterImagePolicy, err error) { result = &v1beta1.ClusterImagePolicy{} err = c.client.Patch(pt). Resource("clusterimagepolicies"). Name(name). SubResource(subresources...). VersionedParams(&opts, scheme.ParameterCodec). Body(data). Do(ctx). Into(result) return } ================================================ FILE: pkg/client/clientset/versioned/typed/policy/v1beta1/doc.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. // This package has the automatically generated typed clients. package v1beta1 ================================================ FILE: pkg/client/clientset/versioned/typed/policy/v1beta1/fake/doc.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. // Package fake has the automatically generated clients. package fake ================================================ FILE: pkg/client/clientset/versioned/typed/policy/v1beta1/fake/fake_clusterimagepolicy.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. package fake import ( "context" v1beta1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1beta1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" labels "k8s.io/apimachinery/pkg/labels" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" testing "k8s.io/client-go/testing" ) // FakeClusterImagePolicies implements ClusterImagePolicyInterface type FakeClusterImagePolicies struct { Fake *FakePolicyV1beta1 } var clusterimagepoliciesResource = v1beta1.SchemeGroupVersion.WithResource("clusterimagepolicies") var clusterimagepoliciesKind = v1beta1.SchemeGroupVersion.WithKind("ClusterImagePolicy") // Get takes name of the clusterImagePolicy, and returns the corresponding clusterImagePolicy object, and an error if there is any. func (c *FakeClusterImagePolicies) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.ClusterImagePolicy, err error) { obj, err := c.Fake. Invokes(testing.NewRootGetAction(clusterimagepoliciesResource, name), &v1beta1.ClusterImagePolicy{}) if obj == nil { return nil, err } return obj.(*v1beta1.ClusterImagePolicy), err } // List takes label and field selectors, and returns the list of ClusterImagePolicies that match those selectors. func (c *FakeClusterImagePolicies) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.ClusterImagePolicyList, err error) { obj, err := c.Fake. Invokes(testing.NewRootListAction(clusterimagepoliciesResource, clusterimagepoliciesKind, opts), &v1beta1.ClusterImagePolicyList{}) if obj == nil { return nil, err } label, _, _ := testing.ExtractFromListOptions(opts) if label == nil { label = labels.Everything() } list := &v1beta1.ClusterImagePolicyList{ListMeta: obj.(*v1beta1.ClusterImagePolicyList).ListMeta} for _, item := range obj.(*v1beta1.ClusterImagePolicyList).Items { if label.Matches(labels.Set(item.Labels)) { list.Items = append(list.Items, item) } } return list, err } // Watch returns a watch.Interface that watches the requested clusterImagePolicies. func (c *FakeClusterImagePolicies) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. InvokesWatch(testing.NewRootWatchAction(clusterimagepoliciesResource, opts)) } // Create takes the representation of a clusterImagePolicy and creates it. Returns the server's representation of the clusterImagePolicy, and an error, if there is any. func (c *FakeClusterImagePolicies) Create(ctx context.Context, clusterImagePolicy *v1beta1.ClusterImagePolicy, opts v1.CreateOptions) (result *v1beta1.ClusterImagePolicy, err error) { obj, err := c.Fake. Invokes(testing.NewRootCreateAction(clusterimagepoliciesResource, clusterImagePolicy), &v1beta1.ClusterImagePolicy{}) if obj == nil { return nil, err } return obj.(*v1beta1.ClusterImagePolicy), err } // Update takes the representation of a clusterImagePolicy and updates it. Returns the server's representation of the clusterImagePolicy, and an error, if there is any. func (c *FakeClusterImagePolicies) Update(ctx context.Context, clusterImagePolicy *v1beta1.ClusterImagePolicy, opts v1.UpdateOptions) (result *v1beta1.ClusterImagePolicy, err error) { obj, err := c.Fake. Invokes(testing.NewRootUpdateAction(clusterimagepoliciesResource, clusterImagePolicy), &v1beta1.ClusterImagePolicy{}) if obj == nil { return nil, err } return obj.(*v1beta1.ClusterImagePolicy), err } // UpdateStatus was generated because the type contains a Status member. // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). func (c *FakeClusterImagePolicies) UpdateStatus(ctx context.Context, clusterImagePolicy *v1beta1.ClusterImagePolicy, opts v1.UpdateOptions) (*v1beta1.ClusterImagePolicy, error) { obj, err := c.Fake. Invokes(testing.NewRootUpdateSubresourceAction(clusterimagepoliciesResource, "status", clusterImagePolicy), &v1beta1.ClusterImagePolicy{}) if obj == nil { return nil, err } return obj.(*v1beta1.ClusterImagePolicy), err } // Delete takes name of the clusterImagePolicy and deletes it. Returns an error if one occurs. func (c *FakeClusterImagePolicies) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. Invokes(testing.NewRootDeleteActionWithOptions(clusterimagepoliciesResource, name, opts), &v1beta1.ClusterImagePolicy{}) return err } // DeleteCollection deletes a collection of objects. func (c *FakeClusterImagePolicies) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { action := testing.NewRootDeleteCollectionAction(clusterimagepoliciesResource, listOpts) _, err := c.Fake.Invokes(action, &v1beta1.ClusterImagePolicyList{}) return err } // Patch applies the patch and returns the patched clusterImagePolicy. func (c *FakeClusterImagePolicies) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.ClusterImagePolicy, err error) { obj, err := c.Fake. Invokes(testing.NewRootPatchSubresourceAction(clusterimagepoliciesResource, name, pt, data, subresources...), &v1beta1.ClusterImagePolicy{}) if obj == nil { return nil, err } return obj.(*v1beta1.ClusterImagePolicy), err } ================================================ FILE: pkg/client/clientset/versioned/typed/policy/v1beta1/fake/fake_policy_client.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. package fake import ( v1beta1 "github.com/sigstore/policy-controller/pkg/client/clientset/versioned/typed/policy/v1beta1" rest "k8s.io/client-go/rest" testing "k8s.io/client-go/testing" ) type FakePolicyV1beta1 struct { *testing.Fake } func (c *FakePolicyV1beta1) ClusterImagePolicies() v1beta1.ClusterImagePolicyInterface { return &FakeClusterImagePolicies{c} } // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. func (c *FakePolicyV1beta1) RESTClient() rest.Interface { var ret *rest.RESTClient return ret } ================================================ FILE: pkg/client/clientset/versioned/typed/policy/v1beta1/generated_expansion.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. package v1beta1 type ClusterImagePolicyExpansion interface{} ================================================ FILE: pkg/client/clientset/versioned/typed/policy/v1beta1/policy_client.go ================================================ // 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. // Code generated by client-gen. DO NOT EDIT. package v1beta1 import ( "net/http" v1beta1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1beta1" "github.com/sigstore/policy-controller/pkg/client/clientset/versioned/scheme" rest "k8s.io/client-go/rest" ) type PolicyV1beta1Interface interface { RESTClient() rest.Interface ClusterImagePoliciesGetter } // PolicyV1beta1Client is used to interact with features provided by the policy.sigstore.dev group. type PolicyV1beta1Client struct { restClient rest.Interface } func (c *PolicyV1beta1Client) ClusterImagePolicies() ClusterImagePolicyInterface { return newClusterImagePolicies(c) } // NewForConfig creates a new PolicyV1beta1Client for the given config. // NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), // where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*PolicyV1beta1Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err } httpClient, err := rest.HTTPClientFor(&config) if err != nil { return nil, err } return NewForConfigAndClient(&config, httpClient) } // NewForConfigAndClient creates a new PolicyV1beta1Client for the given config and http client. // Note the http client provided takes precedence over the configured transport values. func NewForConfigAndClient(c *rest.Config, h *http.Client) (*PolicyV1beta1Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err } client, err := rest.RESTClientForConfigAndClient(&config, h) if err != nil { return nil, err } return &PolicyV1beta1Client{client}, nil } // NewForConfigOrDie creates a new PolicyV1beta1Client for the given config and // panics if there is an error in the config. func NewForConfigOrDie(c *rest.Config) *PolicyV1beta1Client { client, err := NewForConfig(c) if err != nil { panic(err) } return client } // New creates a new PolicyV1beta1Client for the given RESTClient. func New(c rest.Interface) *PolicyV1beta1Client { return &PolicyV1beta1Client{c} } func setConfigDefaults(config *rest.Config) error { gv := v1beta1.SchemeGroupVersion config.GroupVersion = &gv config.APIPath = "/apis" config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() if config.UserAgent == "" { config.UserAgent = rest.DefaultKubernetesUserAgent() } return nil } // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. func (c *PolicyV1beta1Client) RESTClient() rest.Interface { if c == nil { return nil } return c.restClient } ================================================ FILE: pkg/client/informers/externalversions/factory.go ================================================ // 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. // Code generated by informer-gen. DO NOT EDIT. package externalversions import ( reflect "reflect" sync "sync" time "time" versioned "github.com/sigstore/policy-controller/pkg/client/clientset/versioned" internalinterfaces "github.com/sigstore/policy-controller/pkg/client/informers/externalversions/internalinterfaces" policy "github.com/sigstore/policy-controller/pkg/client/informers/externalversions/policy" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" ) // SharedInformerOption defines the functional option type for SharedInformerFactory. type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory type sharedInformerFactory struct { client versioned.Interface namespace string tweakListOptions internalinterfaces.TweakListOptionsFunc lock sync.Mutex defaultResync time.Duration customResync map[reflect.Type]time.Duration informers map[reflect.Type]cache.SharedIndexInformer // startedInformers is used for tracking which informers have been started. // This allows Start() to be called multiple times safely. startedInformers map[reflect.Type]bool // wg tracks how many goroutines were started. wg sync.WaitGroup // shuttingDown is true when Shutdown has been called. It may still be running // because it needs to wait for goroutines. shuttingDown bool } // WithCustomResyncConfig sets a custom resync period for the specified informer types. func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { return func(factory *sharedInformerFactory) *sharedInformerFactory { for k, v := range resyncConfig { factory.customResync[reflect.TypeOf(k)] = v } return factory } } // WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { return func(factory *sharedInformerFactory) *sharedInformerFactory { factory.tweakListOptions = tweakListOptions return factory } } // WithNamespace limits the SharedInformerFactory to the specified namespace. func WithNamespace(namespace string) SharedInformerOption { return func(factory *sharedInformerFactory) *sharedInformerFactory { factory.namespace = namespace return factory } } // NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { return NewSharedInformerFactoryWithOptions(client, defaultResync) } // NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. // Listers obtained via this SharedInformerFactory will be subject to the same filters // as specified here. // Deprecated: Please use NewSharedInformerFactoryWithOptions instead func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) } // NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { factory := &sharedInformerFactory{ client: client, namespace: v1.NamespaceAll, defaultResync: defaultResync, informers: make(map[reflect.Type]cache.SharedIndexInformer), startedInformers: make(map[reflect.Type]bool), customResync: make(map[reflect.Type]time.Duration), } // Apply all options for _, opt := range options { factory = opt(factory) } return factory } func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { f.lock.Lock() defer f.lock.Unlock() if f.shuttingDown { return } for informerType, informer := range f.informers { if !f.startedInformers[informerType] { f.wg.Add(1) // We need a new variable in each loop iteration, // otherwise the goroutine would use the loop variable // and that keeps changing. informer := informer go func() { defer f.wg.Done() informer.Run(stopCh) }() f.startedInformers[informerType] = true } } } func (f *sharedInformerFactory) Shutdown() { f.lock.Lock() f.shuttingDown = true f.lock.Unlock() // Will return immediately if there is nothing to wait for. f.wg.Wait() } func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { informers := func() map[reflect.Type]cache.SharedIndexInformer { f.lock.Lock() defer f.lock.Unlock() informers := map[reflect.Type]cache.SharedIndexInformer{} for informerType, informer := range f.informers { if f.startedInformers[informerType] { informers[informerType] = informer } } return informers }() res := map[reflect.Type]bool{} for informType, informer := range informers { res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) } return res } // InternalInformerFor returns the SharedIndexInformer for obj using an internal // client. func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { f.lock.Lock() defer f.lock.Unlock() informerType := reflect.TypeOf(obj) informer, exists := f.informers[informerType] if exists { return informer } resyncPeriod, exists := f.customResync[informerType] if !exists { resyncPeriod = f.defaultResync } informer = newFunc(f.client, resyncPeriod) f.informers[informerType] = informer return informer } // SharedInformerFactory provides shared informers for resources in all known // API group versions. // // It is typically used like this: // // ctx, cancel := context.Background() // defer cancel() // factory := NewSharedInformerFactory(client, resyncPeriod) // defer factory.WaitForStop() // Returns immediately if nothing was started. // genericInformer := factory.ForResource(resource) // typedInformer := factory.SomeAPIGroup().V1().SomeType() // factory.Start(ctx.Done()) // Start processing these informers. // synced := factory.WaitForCacheSync(ctx.Done()) // for v, ok := range synced { // if !ok { // fmt.Fprintf(os.Stderr, "caches failed to sync: %v", v) // return // } // } // // // Creating informers can also be created after Start, but then // // Start must be called again: // anotherGenericInformer := factory.ForResource(resource) // factory.Start(ctx.Done()) type SharedInformerFactory interface { internalinterfaces.SharedInformerFactory // Start initializes all requested informers. They are handled in goroutines // which run until the stop channel gets closed. Start(stopCh <-chan struct{}) // Shutdown marks a factory as shutting down. At that point no new // informers can be started anymore and Start will return without // doing anything. // // In addition, Shutdown blocks until all goroutines have terminated. For that // to happen, the close channel(s) that they were started with must be closed, // either before Shutdown gets called or while it is waiting. // // Shutdown may be called multiple times, even concurrently. All such calls will // block until all goroutines have terminated. Shutdown() // WaitForCacheSync blocks until all started informers' caches were synced // or the stop channel gets closed. WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool // ForResource gives generic access to a shared informer of the matching type. ForResource(resource schema.GroupVersionResource) (GenericInformer, error) // InternalInformerFor returns the SharedIndexInformer for obj using an internal // client. InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer Policy() policy.Interface } func (f *sharedInformerFactory) Policy() policy.Interface { return policy.New(f, f.namespace, f.tweakListOptions) } ================================================ FILE: pkg/client/informers/externalversions/generic.go ================================================ // 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. // Code generated by informer-gen. DO NOT EDIT. package externalversions import ( "fmt" v1alpha1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" v1beta1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1beta1" schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" ) // GenericInformer is type of SharedIndexInformer which will locate and delegate to other // sharedInformers based on type type GenericInformer interface { Informer() cache.SharedIndexInformer Lister() cache.GenericLister } type genericInformer struct { informer cache.SharedIndexInformer resource schema.GroupResource } // Informer returns the SharedIndexInformer. func (f *genericInformer) Informer() cache.SharedIndexInformer { return f.informer } // Lister returns the GenericLister. func (f *genericInformer) Lister() cache.GenericLister { return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) } // ForResource gives generic access to a shared informer of the matching type // TODO extend this to unknown resources with a client pool func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { switch resource { // Group=policy.sigstore.dev, Version=v1alpha1 case v1alpha1.SchemeGroupVersion.WithResource("clusterimagepolicies"): return &genericInformer{resource: resource.GroupResource(), informer: f.Policy().V1alpha1().ClusterImagePolicies().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("trustroots"): return &genericInformer{resource: resource.GroupResource(), informer: f.Policy().V1alpha1().TrustRoots().Informer()}, nil // Group=policy.sigstore.dev, Version=v1beta1 case v1beta1.SchemeGroupVersion.WithResource("clusterimagepolicies"): return &genericInformer{resource: resource.GroupResource(), informer: f.Policy().V1beta1().ClusterImagePolicies().Informer()}, nil } return nil, fmt.Errorf("no informer found for %v", resource) } ================================================ FILE: pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go ================================================ // 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. // Code generated by informer-gen. DO NOT EDIT. package internalinterfaces import ( time "time" versioned "github.com/sigstore/policy-controller/pkg/client/clientset/versioned" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" cache "k8s.io/client-go/tools/cache" ) // NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer // SharedInformerFactory a small interface to allow for adding an informer without an import cycle type SharedInformerFactory interface { Start(stopCh <-chan struct{}) InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer } // TweakListOptionsFunc is a function that transforms a v1.ListOptions. type TweakListOptionsFunc func(*v1.ListOptions) ================================================ FILE: pkg/client/informers/externalversions/policy/interface.go ================================================ // 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. // Code generated by informer-gen. DO NOT EDIT. package policy import ( internalinterfaces "github.com/sigstore/policy-controller/pkg/client/informers/externalversions/internalinterfaces" v1alpha1 "github.com/sigstore/policy-controller/pkg/client/informers/externalversions/policy/v1alpha1" v1beta1 "github.com/sigstore/policy-controller/pkg/client/informers/externalversions/policy/v1beta1" ) // Interface provides access to each of this group's versions. type Interface interface { // V1alpha1 provides access to shared informers for resources in V1alpha1. V1alpha1() v1alpha1.Interface // V1beta1 provides access to shared informers for resources in V1beta1. V1beta1() v1beta1.Interface } type group struct { factory internalinterfaces.SharedInformerFactory namespace string tweakListOptions internalinterfaces.TweakListOptionsFunc } // New returns a new Interface. func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} } // V1alpha1 returns a new v1alpha1.Interface. func (g *group) V1alpha1() v1alpha1.Interface { return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions) } // V1beta1 returns a new v1beta1.Interface. func (g *group) V1beta1() v1beta1.Interface { return v1beta1.New(g.factory, g.namespace, g.tweakListOptions) } ================================================ FILE: pkg/client/informers/externalversions/policy/v1alpha1/clusterimagepolicy.go ================================================ // 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. // Code generated by informer-gen. DO NOT EDIT. package v1alpha1 import ( "context" time "time" policyv1alpha1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" versioned "github.com/sigstore/policy-controller/pkg/client/clientset/versioned" internalinterfaces "github.com/sigstore/policy-controller/pkg/client/informers/externalversions/internalinterfaces" v1alpha1 "github.com/sigstore/policy-controller/pkg/client/listers/policy/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" watch "k8s.io/apimachinery/pkg/watch" cache "k8s.io/client-go/tools/cache" ) // ClusterImagePolicyInformer provides access to a shared informer and lister for // ClusterImagePolicies. type ClusterImagePolicyInformer interface { Informer() cache.SharedIndexInformer Lister() v1alpha1.ClusterImagePolicyLister } type clusterImagePolicyInformer struct { factory internalinterfaces.SharedInformerFactory tweakListOptions internalinterfaces.TweakListOptionsFunc } // NewClusterImagePolicyInformer constructs a new informer for ClusterImagePolicy type. // Always prefer using an informer factory to get a shared informer instead of getting an independent // one. This reduces memory footprint and number of connections to the server. func NewClusterImagePolicyInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { return NewFilteredClusterImagePolicyInformer(client, resyncPeriod, indexers, nil) } // NewFilteredClusterImagePolicyInformer constructs a new informer for ClusterImagePolicy type. // Always prefer using an informer factory to get a shared informer instead of getting an independent // one. This reduces memory footprint and number of connections to the server. func NewFilteredClusterImagePolicyInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { return cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { if tweakListOptions != nil { tweakListOptions(&options) } return client.PolicyV1alpha1().ClusterImagePolicies().List(context.TODO(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } return client.PolicyV1alpha1().ClusterImagePolicies().Watch(context.TODO(), options) }, }, &policyv1alpha1.ClusterImagePolicy{}, resyncPeriod, indexers, ) } func (f *clusterImagePolicyInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { return NewFilteredClusterImagePolicyInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) } func (f *clusterImagePolicyInformer) Informer() cache.SharedIndexInformer { return f.factory.InformerFor(&policyv1alpha1.ClusterImagePolicy{}, f.defaultInformer) } func (f *clusterImagePolicyInformer) Lister() v1alpha1.ClusterImagePolicyLister { return v1alpha1.NewClusterImagePolicyLister(f.Informer().GetIndexer()) } ================================================ FILE: pkg/client/informers/externalversions/policy/v1alpha1/interface.go ================================================ // 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. // Code generated by informer-gen. DO NOT EDIT. package v1alpha1 import ( internalinterfaces "github.com/sigstore/policy-controller/pkg/client/informers/externalversions/internalinterfaces" ) // Interface provides access to all the informers in this group version. type Interface interface { // ClusterImagePolicies returns a ClusterImagePolicyInformer. ClusterImagePolicies() ClusterImagePolicyInformer // TrustRoots returns a TrustRootInformer. TrustRoots() TrustRootInformer } type version struct { factory internalinterfaces.SharedInformerFactory namespace string tweakListOptions internalinterfaces.TweakListOptionsFunc } // New returns a new Interface. func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} } // ClusterImagePolicies returns a ClusterImagePolicyInformer. func (v *version) ClusterImagePolicies() ClusterImagePolicyInformer { return &clusterImagePolicyInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} } // TrustRoots returns a TrustRootInformer. func (v *version) TrustRoots() TrustRootInformer { return &trustRootInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} } ================================================ FILE: pkg/client/informers/externalversions/policy/v1alpha1/trustroot.go ================================================ // 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. // Code generated by informer-gen. DO NOT EDIT. package v1alpha1 import ( "context" time "time" policyv1alpha1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" versioned "github.com/sigstore/policy-controller/pkg/client/clientset/versioned" internalinterfaces "github.com/sigstore/policy-controller/pkg/client/informers/externalversions/internalinterfaces" v1alpha1 "github.com/sigstore/policy-controller/pkg/client/listers/policy/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" watch "k8s.io/apimachinery/pkg/watch" cache "k8s.io/client-go/tools/cache" ) // TrustRootInformer provides access to a shared informer and lister for // TrustRoots. type TrustRootInformer interface { Informer() cache.SharedIndexInformer Lister() v1alpha1.TrustRootLister } type trustRootInformer struct { factory internalinterfaces.SharedInformerFactory tweakListOptions internalinterfaces.TweakListOptionsFunc } // NewTrustRootInformer constructs a new informer for TrustRoot type. // Always prefer using an informer factory to get a shared informer instead of getting an independent // one. This reduces memory footprint and number of connections to the server. func NewTrustRootInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { return NewFilteredTrustRootInformer(client, resyncPeriod, indexers, nil) } // NewFilteredTrustRootInformer constructs a new informer for TrustRoot type. // Always prefer using an informer factory to get a shared informer instead of getting an independent // one. This reduces memory footprint and number of connections to the server. func NewFilteredTrustRootInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { return cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { if tweakListOptions != nil { tweakListOptions(&options) } return client.PolicyV1alpha1().TrustRoots().List(context.TODO(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } return client.PolicyV1alpha1().TrustRoots().Watch(context.TODO(), options) }, }, &policyv1alpha1.TrustRoot{}, resyncPeriod, indexers, ) } func (f *trustRootInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { return NewFilteredTrustRootInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) } func (f *trustRootInformer) Informer() cache.SharedIndexInformer { return f.factory.InformerFor(&policyv1alpha1.TrustRoot{}, f.defaultInformer) } func (f *trustRootInformer) Lister() v1alpha1.TrustRootLister { return v1alpha1.NewTrustRootLister(f.Informer().GetIndexer()) } ================================================ FILE: pkg/client/informers/externalversions/policy/v1beta1/clusterimagepolicy.go ================================================ // 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. // Code generated by informer-gen. DO NOT EDIT. package v1beta1 import ( "context" time "time" policyv1beta1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1beta1" versioned "github.com/sigstore/policy-controller/pkg/client/clientset/versioned" internalinterfaces "github.com/sigstore/policy-controller/pkg/client/informers/externalversions/internalinterfaces" v1beta1 "github.com/sigstore/policy-controller/pkg/client/listers/policy/v1beta1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" watch "k8s.io/apimachinery/pkg/watch" cache "k8s.io/client-go/tools/cache" ) // ClusterImagePolicyInformer provides access to a shared informer and lister for // ClusterImagePolicies. type ClusterImagePolicyInformer interface { Informer() cache.SharedIndexInformer Lister() v1beta1.ClusterImagePolicyLister } type clusterImagePolicyInformer struct { factory internalinterfaces.SharedInformerFactory tweakListOptions internalinterfaces.TweakListOptionsFunc } // NewClusterImagePolicyInformer constructs a new informer for ClusterImagePolicy type. // Always prefer using an informer factory to get a shared informer instead of getting an independent // one. This reduces memory footprint and number of connections to the server. func NewClusterImagePolicyInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { return NewFilteredClusterImagePolicyInformer(client, resyncPeriod, indexers, nil) } // NewFilteredClusterImagePolicyInformer constructs a new informer for ClusterImagePolicy type. // Always prefer using an informer factory to get a shared informer instead of getting an independent // one. This reduces memory footprint and number of connections to the server. func NewFilteredClusterImagePolicyInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { return cache.NewSharedIndexInformer( &cache.ListWatch{ ListFunc: func(options v1.ListOptions) (runtime.Object, error) { if tweakListOptions != nil { tweakListOptions(&options) } return client.PolicyV1beta1().ClusterImagePolicies().List(context.TODO(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } return client.PolicyV1beta1().ClusterImagePolicies().Watch(context.TODO(), options) }, }, &policyv1beta1.ClusterImagePolicy{}, resyncPeriod, indexers, ) } func (f *clusterImagePolicyInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { return NewFilteredClusterImagePolicyInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) } func (f *clusterImagePolicyInformer) Informer() cache.SharedIndexInformer { return f.factory.InformerFor(&policyv1beta1.ClusterImagePolicy{}, f.defaultInformer) } func (f *clusterImagePolicyInformer) Lister() v1beta1.ClusterImagePolicyLister { return v1beta1.NewClusterImagePolicyLister(f.Informer().GetIndexer()) } ================================================ FILE: pkg/client/informers/externalversions/policy/v1beta1/interface.go ================================================ // 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. // Code generated by informer-gen. DO NOT EDIT. package v1beta1 import ( internalinterfaces "github.com/sigstore/policy-controller/pkg/client/informers/externalversions/internalinterfaces" ) // Interface provides access to all the informers in this group version. type Interface interface { // ClusterImagePolicies returns a ClusterImagePolicyInformer. ClusterImagePolicies() ClusterImagePolicyInformer } type version struct { factory internalinterfaces.SharedInformerFactory namespace string tweakListOptions internalinterfaces.TweakListOptionsFunc } // New returns a new Interface. func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} } // ClusterImagePolicies returns a ClusterImagePolicyInformer. func (v *version) ClusterImagePolicies() ClusterImagePolicyInformer { return &clusterImagePolicyInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} } ================================================ FILE: pkg/client/injection/client/client.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package client import ( context "context" versioned "github.com/sigstore/policy-controller/pkg/client/clientset/versioned" rest "k8s.io/client-go/rest" injection "knative.dev/pkg/injection" logging "knative.dev/pkg/logging" ) func init() { injection.Default.RegisterClient(withClientFromConfig) injection.Default.RegisterClientFetcher(func(ctx context.Context) interface{} { return Get(ctx) }) } // Key is used as the key for associating information with a context.Context. type Key struct{} func withClientFromConfig(ctx context.Context, cfg *rest.Config) context.Context { return context.WithValue(ctx, Key{}, versioned.NewForConfigOrDie(cfg)) } // Get extracts the versioned.Interface client from the context. func Get(ctx context.Context) versioned.Interface { untyped := ctx.Value(Key{}) if untyped == nil { if injection.GetConfig(ctx) == nil { logging.FromContext(ctx).Panic( "Unable to fetch github.com/sigstore/policy-controller/pkg/client/clientset/versioned.Interface from context. This context is not the application context (which is typically given to constructors via sharedmain).") } else { logging.FromContext(ctx).Panic( "Unable to fetch github.com/sigstore/policy-controller/pkg/client/clientset/versioned.Interface from context.") } } return untyped.(versioned.Interface) } ================================================ FILE: pkg/client/injection/client/fake/fake.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package fake import ( context "context" fake "github.com/sigstore/policy-controller/pkg/client/clientset/versioned/fake" client "github.com/sigstore/policy-controller/pkg/client/injection/client" runtime "k8s.io/apimachinery/pkg/runtime" rest "k8s.io/client-go/rest" injection "knative.dev/pkg/injection" logging "knative.dev/pkg/logging" ) func init() { injection.Fake.RegisterClient(withClient) injection.Fake.RegisterClientFetcher(func(ctx context.Context) interface{} { return Get(ctx) }) } func withClient(ctx context.Context, cfg *rest.Config) context.Context { ctx, _ = With(ctx) return ctx } func With(ctx context.Context, objects ...runtime.Object) (context.Context, *fake.Clientset) { cs := fake.NewSimpleClientset(objects...) return context.WithValue(ctx, client.Key{}, cs), cs } // Get extracts the Kubernetes client from the context. func Get(ctx context.Context) *fake.Clientset { untyped := ctx.Value(client.Key{}) if untyped == nil { logging.FromContext(ctx).Panic( "Unable to fetch github.com/sigstore/policy-controller/pkg/client/clientset/versioned/fake.Clientset from context.") } return untyped.(*fake.Clientset) } ================================================ FILE: pkg/client/injection/ducks/duck/v1beta1/podscalable/fake/fake.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package fake import ( podscalable "github.com/sigstore/policy-controller/pkg/client/injection/ducks/duck/v1beta1/podscalable" injection "knative.dev/pkg/injection" ) var Get = podscalable.Get func init() { injection.Fake.RegisterDuck(podscalable.WithDuck) } ================================================ FILE: pkg/client/injection/ducks/duck/v1beta1/podscalable/podscalable.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package podscalable import ( context "context" v1beta1 "github.com/sigstore/policy-controller/pkg/apis/duck/v1beta1" duck "knative.dev/pkg/apis/duck" controller "knative.dev/pkg/controller" injection "knative.dev/pkg/injection" dynamicclient "knative.dev/pkg/injection/clients/dynamicclient" logging "knative.dev/pkg/logging" ) func init() { injection.Default.RegisterDuck(WithDuck) } // Key is used for associating the Informer inside the context.Context. type Key struct{} func WithDuck(ctx context.Context) context.Context { dc := dynamicclient.Get(ctx) dif := &duck.CachedInformerFactory{ Delegate: &duck.TypedInformerFactory{ Client: dc, Type: (&v1beta1.PodScalable{}).GetFullType(), ResyncPeriod: controller.GetResyncPeriod(ctx), StopChannel: ctx.Done(), }, } return context.WithValue(ctx, Key{}, dif) } // Get extracts the typed informer from the context. func Get(ctx context.Context) duck.InformerFactory { untyped := ctx.Value(Key{}) if untyped == nil { logging.FromContext(ctx).Panic( "Unable to fetch knative.dev/pkg/apis/duck.InformerFactory from context.") } return untyped.(duck.InformerFactory) } ================================================ FILE: pkg/client/injection/informers/factory/factory.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package factory import ( context "context" externalversions "github.com/sigstore/policy-controller/pkg/client/informers/externalversions" client "github.com/sigstore/policy-controller/pkg/client/injection/client" controller "knative.dev/pkg/controller" injection "knative.dev/pkg/injection" logging "knative.dev/pkg/logging" ) func init() { injection.Default.RegisterInformerFactory(withInformerFactory) } // Key is used as the key for associating information with a context.Context. type Key struct{} func withInformerFactory(ctx context.Context) context.Context { c := client.Get(ctx) opts := make([]externalversions.SharedInformerOption, 0, 1) if injection.HasNamespaceScope(ctx) { opts = append(opts, externalversions.WithNamespace(injection.GetNamespaceScope(ctx))) } return context.WithValue(ctx, Key{}, externalversions.NewSharedInformerFactoryWithOptions(c, controller.GetResyncPeriod(ctx), opts...)) } // Get extracts the InformerFactory from the context. func Get(ctx context.Context) externalversions.SharedInformerFactory { untyped := ctx.Value(Key{}) if untyped == nil { logging.FromContext(ctx).Panic( "Unable to fetch github.com/sigstore/policy-controller/pkg/client/informers/externalversions.SharedInformerFactory from context.") } return untyped.(externalversions.SharedInformerFactory) } ================================================ FILE: pkg/client/injection/informers/factory/fake/fake.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package fake import ( context "context" externalversions "github.com/sigstore/policy-controller/pkg/client/informers/externalversions" fake "github.com/sigstore/policy-controller/pkg/client/injection/client/fake" factory "github.com/sigstore/policy-controller/pkg/client/injection/informers/factory" controller "knative.dev/pkg/controller" injection "knative.dev/pkg/injection" ) var Get = factory.Get func init() { injection.Fake.RegisterInformerFactory(withInformerFactory) } func withInformerFactory(ctx context.Context) context.Context { c := fake.Get(ctx) opts := make([]externalversions.SharedInformerOption, 0, 1) if injection.HasNamespaceScope(ctx) { opts = append(opts, externalversions.WithNamespace(injection.GetNamespaceScope(ctx))) } return context.WithValue(ctx, factory.Key{}, externalversions.NewSharedInformerFactoryWithOptions(c, controller.GetResyncPeriod(ctx), opts...)) } ================================================ FILE: pkg/client/injection/informers/factory/filtered/fake/fake_filtered_factory.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package fakeFilteredFactory import ( context "context" externalversions "github.com/sigstore/policy-controller/pkg/client/informers/externalversions" fake "github.com/sigstore/policy-controller/pkg/client/injection/client/fake" filtered "github.com/sigstore/policy-controller/pkg/client/injection/informers/factory/filtered" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" controller "knative.dev/pkg/controller" injection "knative.dev/pkg/injection" logging "knative.dev/pkg/logging" ) var Get = filtered.Get func init() { injection.Fake.RegisterInformerFactory(withInformerFactory) } func withInformerFactory(ctx context.Context) context.Context { c := fake.Get(ctx) untyped := ctx.Value(filtered.LabelKey{}) if untyped == nil { logging.FromContext(ctx).Panic( "Unable to fetch labelkey from context.") } labelSelectors := untyped.([]string) for _, selector := range labelSelectors { opts := []externalversions.SharedInformerOption{} if injection.HasNamespaceScope(ctx) { opts = append(opts, externalversions.WithNamespace(injection.GetNamespaceScope(ctx))) } opts = append(opts, externalversions.WithTweakListOptions(func(l *v1.ListOptions) { l.LabelSelector = selector })) ctx = context.WithValue(ctx, filtered.Key{Selector: selector}, externalversions.NewSharedInformerFactoryWithOptions(c, controller.GetResyncPeriod(ctx), opts...)) } return ctx } ================================================ FILE: pkg/client/injection/informers/factory/filtered/filtered_factory.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package filteredFactory import ( context "context" externalversions "github.com/sigstore/policy-controller/pkg/client/informers/externalversions" client "github.com/sigstore/policy-controller/pkg/client/injection/client" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" controller "knative.dev/pkg/controller" injection "knative.dev/pkg/injection" logging "knative.dev/pkg/logging" ) func init() { injection.Default.RegisterInformerFactory(withInformerFactory) } // Key is used as the key for associating information with a context.Context. type Key struct { Selector string } type LabelKey struct{} func WithSelectors(ctx context.Context, selector ...string) context.Context { return context.WithValue(ctx, LabelKey{}, selector) } func withInformerFactory(ctx context.Context) context.Context { c := client.Get(ctx) untyped := ctx.Value(LabelKey{}) if untyped == nil { logging.FromContext(ctx).Panic( "Unable to fetch labelkey from context.") } labelSelectors := untyped.([]string) for _, selector := range labelSelectors { opts := []externalversions.SharedInformerOption{} if injection.HasNamespaceScope(ctx) { opts = append(opts, externalversions.WithNamespace(injection.GetNamespaceScope(ctx))) } opts = append(opts, externalversions.WithTweakListOptions(func(l *v1.ListOptions) { l.LabelSelector = selector })) ctx = context.WithValue(ctx, Key{Selector: selector}, externalversions.NewSharedInformerFactoryWithOptions(c, controller.GetResyncPeriod(ctx), opts...)) } return ctx } // Get extracts the InformerFactory from the context. func Get(ctx context.Context, selector string) externalversions.SharedInformerFactory { untyped := ctx.Value(Key{Selector: selector}) if untyped == nil { logging.FromContext(ctx).Panicf( "Unable to fetch github.com/sigstore/policy-controller/pkg/client/informers/externalversions.SharedInformerFactory with selector %s from context.", selector) } return untyped.(externalversions.SharedInformerFactory) } ================================================ FILE: pkg/client/injection/informers/policy/v1alpha1/clusterimagepolicy/clusterimagepolicy.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package clusterimagepolicy import ( context "context" v1alpha1 "github.com/sigstore/policy-controller/pkg/client/informers/externalversions/policy/v1alpha1" factory "github.com/sigstore/policy-controller/pkg/client/injection/informers/factory" controller "knative.dev/pkg/controller" injection "knative.dev/pkg/injection" logging "knative.dev/pkg/logging" ) func init() { injection.Default.RegisterInformer(withInformer) } // Key is used for associating the Informer inside the context.Context. type Key struct{} func withInformer(ctx context.Context) (context.Context, controller.Informer) { f := factory.Get(ctx) inf := f.Policy().V1alpha1().ClusterImagePolicies() return context.WithValue(ctx, Key{}, inf), inf.Informer() } // Get extracts the typed informer from the context. func Get(ctx context.Context) v1alpha1.ClusterImagePolicyInformer { untyped := ctx.Value(Key{}) if untyped == nil { logging.FromContext(ctx).Panic( "Unable to fetch github.com/sigstore/policy-controller/pkg/client/informers/externalversions/policy/v1alpha1.ClusterImagePolicyInformer from context.") } return untyped.(v1alpha1.ClusterImagePolicyInformer) } ================================================ FILE: pkg/client/injection/informers/policy/v1alpha1/clusterimagepolicy/fake/fake.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package fake import ( context "context" fake "github.com/sigstore/policy-controller/pkg/client/injection/informers/factory/fake" clusterimagepolicy "github.com/sigstore/policy-controller/pkg/client/injection/informers/policy/v1alpha1/clusterimagepolicy" controller "knative.dev/pkg/controller" injection "knative.dev/pkg/injection" ) var Get = clusterimagepolicy.Get func init() { injection.Fake.RegisterInformer(withInformer) } func withInformer(ctx context.Context) (context.Context, controller.Informer) { f := fake.Get(ctx) inf := f.Policy().V1alpha1().ClusterImagePolicies() return context.WithValue(ctx, clusterimagepolicy.Key{}, inf), inf.Informer() } ================================================ FILE: pkg/client/injection/informers/policy/v1alpha1/clusterimagepolicy/filtered/clusterimagepolicy.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package filtered import ( context "context" v1alpha1 "github.com/sigstore/policy-controller/pkg/client/informers/externalversions/policy/v1alpha1" filtered "github.com/sigstore/policy-controller/pkg/client/injection/informers/factory/filtered" controller "knative.dev/pkg/controller" injection "knative.dev/pkg/injection" logging "knative.dev/pkg/logging" ) func init() { injection.Default.RegisterFilteredInformers(withInformer) } // Key is used for associating the Informer inside the context.Context. type Key struct { Selector string } func withInformer(ctx context.Context) (context.Context, []controller.Informer) { untyped := ctx.Value(filtered.LabelKey{}) if untyped == nil { logging.FromContext(ctx).Panic( "Unable to fetch labelkey from context.") } labelSelectors := untyped.([]string) infs := []controller.Informer{} for _, selector := range labelSelectors { f := filtered.Get(ctx, selector) inf := f.Policy().V1alpha1().ClusterImagePolicies() ctx = context.WithValue(ctx, Key{Selector: selector}, inf) infs = append(infs, inf.Informer()) } return ctx, infs } // Get extracts the typed informer from the context. func Get(ctx context.Context, selector string) v1alpha1.ClusterImagePolicyInformer { untyped := ctx.Value(Key{Selector: selector}) if untyped == nil { logging.FromContext(ctx).Panicf( "Unable to fetch github.com/sigstore/policy-controller/pkg/client/informers/externalversions/policy/v1alpha1.ClusterImagePolicyInformer with selector %s from context.", selector) } return untyped.(v1alpha1.ClusterImagePolicyInformer) } ================================================ FILE: pkg/client/injection/informers/policy/v1alpha1/clusterimagepolicy/filtered/fake/fake.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package fake import ( context "context" factoryfiltered "github.com/sigstore/policy-controller/pkg/client/injection/informers/factory/filtered" filtered "github.com/sigstore/policy-controller/pkg/client/injection/informers/policy/v1alpha1/clusterimagepolicy/filtered" controller "knative.dev/pkg/controller" injection "knative.dev/pkg/injection" logging "knative.dev/pkg/logging" ) var Get = filtered.Get func init() { injection.Fake.RegisterFilteredInformers(withInformer) } func withInformer(ctx context.Context) (context.Context, []controller.Informer) { untyped := ctx.Value(factoryfiltered.LabelKey{}) if untyped == nil { logging.FromContext(ctx).Panic( "Unable to fetch labelkey from context.") } labelSelectors := untyped.([]string) infs := []controller.Informer{} for _, selector := range labelSelectors { f := factoryfiltered.Get(ctx, selector) inf := f.Policy().V1alpha1().ClusterImagePolicies() ctx = context.WithValue(ctx, filtered.Key{Selector: selector}, inf) infs = append(infs, inf.Informer()) } return ctx, infs } ================================================ FILE: pkg/client/injection/informers/policy/v1alpha1/trustroot/fake/fake.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package fake import ( context "context" fake "github.com/sigstore/policy-controller/pkg/client/injection/informers/factory/fake" trustroot "github.com/sigstore/policy-controller/pkg/client/injection/informers/policy/v1alpha1/trustroot" controller "knative.dev/pkg/controller" injection "knative.dev/pkg/injection" ) var Get = trustroot.Get func init() { injection.Fake.RegisterInformer(withInformer) } func withInformer(ctx context.Context) (context.Context, controller.Informer) { f := fake.Get(ctx) inf := f.Policy().V1alpha1().TrustRoots() return context.WithValue(ctx, trustroot.Key{}, inf), inf.Informer() } ================================================ FILE: pkg/client/injection/informers/policy/v1alpha1/trustroot/filtered/fake/fake.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package fake import ( context "context" factoryfiltered "github.com/sigstore/policy-controller/pkg/client/injection/informers/factory/filtered" filtered "github.com/sigstore/policy-controller/pkg/client/injection/informers/policy/v1alpha1/trustroot/filtered" controller "knative.dev/pkg/controller" injection "knative.dev/pkg/injection" logging "knative.dev/pkg/logging" ) var Get = filtered.Get func init() { injection.Fake.RegisterFilteredInformers(withInformer) } func withInformer(ctx context.Context) (context.Context, []controller.Informer) { untyped := ctx.Value(factoryfiltered.LabelKey{}) if untyped == nil { logging.FromContext(ctx).Panic( "Unable to fetch labelkey from context.") } labelSelectors := untyped.([]string) infs := []controller.Informer{} for _, selector := range labelSelectors { f := factoryfiltered.Get(ctx, selector) inf := f.Policy().V1alpha1().TrustRoots() ctx = context.WithValue(ctx, filtered.Key{Selector: selector}, inf) infs = append(infs, inf.Informer()) } return ctx, infs } ================================================ FILE: pkg/client/injection/informers/policy/v1alpha1/trustroot/filtered/trustroot.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package filtered import ( context "context" v1alpha1 "github.com/sigstore/policy-controller/pkg/client/informers/externalversions/policy/v1alpha1" filtered "github.com/sigstore/policy-controller/pkg/client/injection/informers/factory/filtered" controller "knative.dev/pkg/controller" injection "knative.dev/pkg/injection" logging "knative.dev/pkg/logging" ) func init() { injection.Default.RegisterFilteredInformers(withInformer) } // Key is used for associating the Informer inside the context.Context. type Key struct { Selector string } func withInformer(ctx context.Context) (context.Context, []controller.Informer) { untyped := ctx.Value(filtered.LabelKey{}) if untyped == nil { logging.FromContext(ctx).Panic( "Unable to fetch labelkey from context.") } labelSelectors := untyped.([]string) infs := []controller.Informer{} for _, selector := range labelSelectors { f := filtered.Get(ctx, selector) inf := f.Policy().V1alpha1().TrustRoots() ctx = context.WithValue(ctx, Key{Selector: selector}, inf) infs = append(infs, inf.Informer()) } return ctx, infs } // Get extracts the typed informer from the context. func Get(ctx context.Context, selector string) v1alpha1.TrustRootInformer { untyped := ctx.Value(Key{Selector: selector}) if untyped == nil { logging.FromContext(ctx).Panicf( "Unable to fetch github.com/sigstore/policy-controller/pkg/client/informers/externalversions/policy/v1alpha1.TrustRootInformer with selector %s from context.", selector) } return untyped.(v1alpha1.TrustRootInformer) } ================================================ FILE: pkg/client/injection/informers/policy/v1alpha1/trustroot/trustroot.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package trustroot import ( context "context" v1alpha1 "github.com/sigstore/policy-controller/pkg/client/informers/externalversions/policy/v1alpha1" factory "github.com/sigstore/policy-controller/pkg/client/injection/informers/factory" controller "knative.dev/pkg/controller" injection "knative.dev/pkg/injection" logging "knative.dev/pkg/logging" ) func init() { injection.Default.RegisterInformer(withInformer) } // Key is used for associating the Informer inside the context.Context. type Key struct{} func withInformer(ctx context.Context) (context.Context, controller.Informer) { f := factory.Get(ctx) inf := f.Policy().V1alpha1().TrustRoots() return context.WithValue(ctx, Key{}, inf), inf.Informer() } // Get extracts the typed informer from the context. func Get(ctx context.Context) v1alpha1.TrustRootInformer { untyped := ctx.Value(Key{}) if untyped == nil { logging.FromContext(ctx).Panic( "Unable to fetch github.com/sigstore/policy-controller/pkg/client/informers/externalversions/policy/v1alpha1.TrustRootInformer from context.") } return untyped.(v1alpha1.TrustRootInformer) } ================================================ FILE: pkg/client/injection/informers/policy/v1beta1/clusterimagepolicy/clusterimagepolicy.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package clusterimagepolicy import ( context "context" v1beta1 "github.com/sigstore/policy-controller/pkg/client/informers/externalversions/policy/v1beta1" factory "github.com/sigstore/policy-controller/pkg/client/injection/informers/factory" controller "knative.dev/pkg/controller" injection "knative.dev/pkg/injection" logging "knative.dev/pkg/logging" ) func init() { injection.Default.RegisterInformer(withInformer) } // Key is used for associating the Informer inside the context.Context. type Key struct{} func withInformer(ctx context.Context) (context.Context, controller.Informer) { f := factory.Get(ctx) inf := f.Policy().V1beta1().ClusterImagePolicies() return context.WithValue(ctx, Key{}, inf), inf.Informer() } // Get extracts the typed informer from the context. func Get(ctx context.Context) v1beta1.ClusterImagePolicyInformer { untyped := ctx.Value(Key{}) if untyped == nil { logging.FromContext(ctx).Panic( "Unable to fetch github.com/sigstore/policy-controller/pkg/client/informers/externalversions/policy/v1beta1.ClusterImagePolicyInformer from context.") } return untyped.(v1beta1.ClusterImagePolicyInformer) } ================================================ FILE: pkg/client/injection/informers/policy/v1beta1/clusterimagepolicy/fake/fake.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package fake import ( context "context" fake "github.com/sigstore/policy-controller/pkg/client/injection/informers/factory/fake" clusterimagepolicy "github.com/sigstore/policy-controller/pkg/client/injection/informers/policy/v1beta1/clusterimagepolicy" controller "knative.dev/pkg/controller" injection "knative.dev/pkg/injection" ) var Get = clusterimagepolicy.Get func init() { injection.Fake.RegisterInformer(withInformer) } func withInformer(ctx context.Context) (context.Context, controller.Informer) { f := fake.Get(ctx) inf := f.Policy().V1beta1().ClusterImagePolicies() return context.WithValue(ctx, clusterimagepolicy.Key{}, inf), inf.Informer() } ================================================ FILE: pkg/client/injection/informers/policy/v1beta1/clusterimagepolicy/filtered/clusterimagepolicy.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package filtered import ( context "context" v1beta1 "github.com/sigstore/policy-controller/pkg/client/informers/externalversions/policy/v1beta1" filtered "github.com/sigstore/policy-controller/pkg/client/injection/informers/factory/filtered" controller "knative.dev/pkg/controller" injection "knative.dev/pkg/injection" logging "knative.dev/pkg/logging" ) func init() { injection.Default.RegisterFilteredInformers(withInformer) } // Key is used for associating the Informer inside the context.Context. type Key struct { Selector string } func withInformer(ctx context.Context) (context.Context, []controller.Informer) { untyped := ctx.Value(filtered.LabelKey{}) if untyped == nil { logging.FromContext(ctx).Panic( "Unable to fetch labelkey from context.") } labelSelectors := untyped.([]string) infs := []controller.Informer{} for _, selector := range labelSelectors { f := filtered.Get(ctx, selector) inf := f.Policy().V1beta1().ClusterImagePolicies() ctx = context.WithValue(ctx, Key{Selector: selector}, inf) infs = append(infs, inf.Informer()) } return ctx, infs } // Get extracts the typed informer from the context. func Get(ctx context.Context, selector string) v1beta1.ClusterImagePolicyInformer { untyped := ctx.Value(Key{Selector: selector}) if untyped == nil { logging.FromContext(ctx).Panicf( "Unable to fetch github.com/sigstore/policy-controller/pkg/client/informers/externalversions/policy/v1beta1.ClusterImagePolicyInformer with selector %s from context.", selector) } return untyped.(v1beta1.ClusterImagePolicyInformer) } ================================================ FILE: pkg/client/injection/informers/policy/v1beta1/clusterimagepolicy/filtered/fake/fake.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package fake import ( context "context" factoryfiltered "github.com/sigstore/policy-controller/pkg/client/injection/informers/factory/filtered" filtered "github.com/sigstore/policy-controller/pkg/client/injection/informers/policy/v1beta1/clusterimagepolicy/filtered" controller "knative.dev/pkg/controller" injection "knative.dev/pkg/injection" logging "knative.dev/pkg/logging" ) var Get = filtered.Get func init() { injection.Fake.RegisterFilteredInformers(withInformer) } func withInformer(ctx context.Context) (context.Context, []controller.Informer) { untyped := ctx.Value(factoryfiltered.LabelKey{}) if untyped == nil { logging.FromContext(ctx).Panic( "Unable to fetch labelkey from context.") } labelSelectors := untyped.([]string) infs := []controller.Informer{} for _, selector := range labelSelectors { f := factoryfiltered.Get(ctx, selector) inf := f.Policy().V1beta1().ClusterImagePolicies() ctx = context.WithValue(ctx, filtered.Key{Selector: selector}, inf) infs = append(infs, inf.Informer()) } return ctx, infs } ================================================ FILE: pkg/client/injection/reconciler/policy/v1alpha1/clusterimagepolicy/controller.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package clusterimagepolicy import ( context "context" fmt "fmt" reflect "reflect" strings "strings" versionedscheme "github.com/sigstore/policy-controller/pkg/client/clientset/versioned/scheme" client "github.com/sigstore/policy-controller/pkg/client/injection/client" clusterimagepolicy "github.com/sigstore/policy-controller/pkg/client/injection/informers/policy/v1alpha1/clusterimagepolicy" zap "go.uber.org/zap" corev1 "k8s.io/api/core/v1" labels "k8s.io/apimachinery/pkg/labels" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" scheme "k8s.io/client-go/kubernetes/scheme" v1 "k8s.io/client-go/kubernetes/typed/core/v1" record "k8s.io/client-go/tools/record" kubeclient "knative.dev/pkg/client/injection/kube/client" controller "knative.dev/pkg/controller" logging "knative.dev/pkg/logging" logkey "knative.dev/pkg/logging/logkey" reconciler "knative.dev/pkg/reconciler" ) const ( defaultControllerAgentName = "clusterimagepolicy-controller" defaultFinalizerName = "clusterimagepolicies.policy.sigstore.dev" ) // NewImpl returns a controller.Impl that handles queuing and feeding work from // the queue through an implementation of controller.Reconciler, delegating to // the provided Interface and optional Finalizer methods. OptionsFn is used to return // controller.ControllerOptions to be used by the internal reconciler. func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { logger := logging.FromContext(ctx) // Check the options function input. It should be 0 or 1. if len(optionsFns) > 1 { logger.Fatal("Up to one options function is supported, found: ", len(optionsFns)) } clusterimagepolicyInformer := clusterimagepolicy.Get(ctx) lister := clusterimagepolicyInformer.Lister() var promoteFilterFunc func(obj interface{}) bool var promoteFunc = func(bkt reconciler.Bucket) {} rec := &reconcilerImpl{ LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { // Signal promotion event promoteFunc(bkt) all, err := lister.List(labels.Everything()) if err != nil { return err } for _, elt := range all { if promoteFilterFunc != nil { if ok := promoteFilterFunc(elt); !ok { continue } } enq(bkt, types.NamespacedName{ Namespace: elt.GetNamespace(), Name: elt.GetName(), }) } return nil }, }, Client: client.Get(ctx), Lister: lister, reconciler: r, finalizerName: defaultFinalizerName, } ctrType := reflect.TypeOf(r).Elem() ctrTypeName := fmt.Sprintf("%s.%s", ctrType.PkgPath(), ctrType.Name()) ctrTypeName = strings.ReplaceAll(ctrTypeName, "/", ".") logger = logger.With( zap.String(logkey.ControllerType, ctrTypeName), zap.String(logkey.Kind, "policy.sigstore.dev.ClusterImagePolicy"), ) impl := controller.NewContext(ctx, rec, controller.ControllerOptions{WorkQueueName: ctrTypeName, Logger: logger}) agentName := defaultControllerAgentName // Pass impl to the options. Save any optional results. for _, fn := range optionsFns { opts := fn(impl) if opts.ConfigStore != nil { rec.configStore = opts.ConfigStore } if opts.FinalizerName != "" { rec.finalizerName = opts.FinalizerName } if opts.AgentName != "" { agentName = opts.AgentName } if opts.SkipStatusUpdates { rec.skipStatusUpdates = true } if opts.DemoteFunc != nil { rec.DemoteFunc = opts.DemoteFunc } if opts.PromoteFilterFunc != nil { promoteFilterFunc = opts.PromoteFilterFunc } if opts.PromoteFunc != nil { promoteFunc = opts.PromoteFunc } } rec.Recorder = createRecorder(ctx, agentName) return impl } func createRecorder(ctx context.Context, agentName string) record.EventRecorder { logger := logging.FromContext(ctx) recorder := controller.GetEventRecorder(ctx) if recorder == nil { // Create event broadcaster logger.Debug("Creating event broadcaster") eventBroadcaster := record.NewBroadcaster() watches := []watch.Interface{ eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), eventBroadcaster.StartRecordingToSink( &v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}), } recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) go func() { <-ctx.Done() for _, w := range watches { w.Stop() } }() } return recorder } func init() { versionedscheme.AddToScheme(scheme.Scheme) } ================================================ FILE: pkg/client/injection/reconciler/policy/v1alpha1/clusterimagepolicy/reconciler.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package clusterimagepolicy import ( context "context" json "encoding/json" fmt "fmt" v1alpha1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" versioned "github.com/sigstore/policy-controller/pkg/client/clientset/versioned" policyv1alpha1 "github.com/sigstore/policy-controller/pkg/client/listers/policy/v1alpha1" zap "go.uber.org/zap" "go.uber.org/zap/zapcore" v1 "k8s.io/api/core/v1" equality "k8s.io/apimachinery/pkg/api/equality" errors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" labels "k8s.io/apimachinery/pkg/labels" types "k8s.io/apimachinery/pkg/types" sets "k8s.io/apimachinery/pkg/util/sets" record "k8s.io/client-go/tools/record" controller "knative.dev/pkg/controller" kmp "knative.dev/pkg/kmp" logging "knative.dev/pkg/logging" reconciler "knative.dev/pkg/reconciler" ) // Interface defines the strongly typed interfaces to be implemented by a // controller reconciling v1alpha1.ClusterImagePolicy. type Interface interface { // ReconcileKind implements custom logic to reconcile v1alpha1.ClusterImagePolicy. Any changes // to the objects .Status or .Finalizers will be propagated to the stored // object. It is recommended that implementors do not call any update calls // for the Kind inside of ReconcileKind, it is the responsibility of the calling // controller to propagate those properties. The resource passed to ReconcileKind // will always have an empty deletion timestamp. ReconcileKind(ctx context.Context, o *v1alpha1.ClusterImagePolicy) reconciler.Event } // Finalizer defines the strongly typed interfaces to be implemented by a // controller finalizing v1alpha1.ClusterImagePolicy. type Finalizer interface { // FinalizeKind implements custom logic to finalize v1alpha1.ClusterImagePolicy. Any changes // to the objects .Status or .Finalizers will be ignored. Returning a nil or // Normal type reconciler.Event will allow the finalizer to be deleted on // the resource. The resource passed to FinalizeKind will always have a set // deletion timestamp. FinalizeKind(ctx context.Context, o *v1alpha1.ClusterImagePolicy) reconciler.Event } // ReadOnlyInterface defines the strongly typed interfaces to be implemented by a // controller reconciling v1alpha1.ClusterImagePolicy if they want to process resources for which // they are not the leader. type ReadOnlyInterface interface { // ObserveKind implements logic to observe v1alpha1.ClusterImagePolicy. // This method should not write to the API. ObserveKind(ctx context.Context, o *v1alpha1.ClusterImagePolicy) reconciler.Event } type doReconcile func(ctx context.Context, o *v1alpha1.ClusterImagePolicy) reconciler.Event // reconcilerImpl implements controller.Reconciler for v1alpha1.ClusterImagePolicy resources. type reconcilerImpl struct { // LeaderAwareFuncs is inlined to help us implement reconciler.LeaderAware. reconciler.LeaderAwareFuncs // Client is used to write back status updates. Client versioned.Interface // Listers index properties about resources. Lister policyv1alpha1.ClusterImagePolicyLister // Recorder is an event recorder for recording Event resources to the // Kubernetes API. Recorder record.EventRecorder // configStore allows for decorating a context with config maps. // +optional configStore reconciler.ConfigStore // reconciler is the implementation of the business logic of the resource. reconciler Interface // finalizerName is the name of the finalizer to reconcile. finalizerName string // skipStatusUpdates configures whether or not this reconciler automatically updates // the status of the reconciled resource. skipStatusUpdates bool } // Check that our Reconciler implements controller.Reconciler. var _ controller.Reconciler = (*reconcilerImpl)(nil) // Check that our generated Reconciler is always LeaderAware. var _ reconciler.LeaderAware = (*reconcilerImpl)(nil) func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister policyv1alpha1.ClusterImagePolicyLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { // Check the options function input. It should be 0 or 1. if len(options) > 1 { logger.Fatal("Up to one options struct is supported, found: ", len(options)) } // Fail fast when users inadvertently implement the other LeaderAware interface. // For the typed reconcilers, Promote shouldn't take any arguments. if _, ok := r.(reconciler.LeaderAware); ok { logger.Fatalf("%T implements the incorrect LeaderAware interface. Promote() should not take an argument as genreconciler handles the enqueuing automatically.", r) } rec := &reconcilerImpl{ LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { all, err := lister.List(labels.Everything()) if err != nil { return err } for _, elt := range all { // TODO: Consider letting users specify a filter in options. enq(bkt, types.NamespacedName{ Namespace: elt.GetNamespace(), Name: elt.GetName(), }) } return nil }, }, Client: client, Lister: lister, Recorder: recorder, reconciler: r, finalizerName: defaultFinalizerName, } for _, opts := range options { if opts.ConfigStore != nil { rec.configStore = opts.ConfigStore } if opts.FinalizerName != "" { rec.finalizerName = opts.FinalizerName } if opts.SkipStatusUpdates { rec.skipStatusUpdates = true } if opts.DemoteFunc != nil { rec.DemoteFunc = opts.DemoteFunc } } return rec } // Reconcile implements controller.Reconciler func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { logger := logging.FromContext(ctx) // Initialize the reconciler state. This will convert the namespace/name // string into a distinct namespace and name, determine if this instance of // the reconciler is the leader, and any additional interfaces implemented // by the reconciler. Returns an error is the resource key is invalid. s, err := newState(key, r) if err != nil { logger.Error("Invalid resource key: ", key) return nil } // If we are not the leader, and we don't implement either ReadOnly // observer interfaces, then take a fast-path out. if s.isNotLeaderNorObserver() { return controller.NewSkipKey(key) } // If configStore is set, attach the frozen configuration to the context. if r.configStore != nil { ctx = r.configStore.ToContext(ctx) } // Add the recorder to context. ctx = controller.WithEventRecorder(ctx, r.Recorder) // Get the resource with this namespace/name. getter := r.Lister original, err := getter.Get(s.name) if errors.IsNotFound(err) { // The resource may no longer exist, in which case we stop processing and call // the ObserveDeletion handler if appropriate. logger.Debugf("Resource %q no longer exists", key) if del, ok := r.reconciler.(reconciler.OnDeletionInterface); ok { return del.ObserveDeletion(ctx, types.NamespacedName{ Namespace: s.namespace, Name: s.name, }) } return nil } else if err != nil { return err } // Don't modify the informers copy. resource := original.DeepCopy() var reconcileEvent reconciler.Event name, do := s.reconcileMethodFor(resource) // Append the target method to the logger. logger = logger.With(zap.String("targetMethod", name)) switch name { case reconciler.DoReconcileKind: // Set and update the finalizer on resource if r.reconciler // implements Finalizer. if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { return fmt.Errorf("failed to set finalizers: %w", err) } if !r.skipStatusUpdates { reconciler.PreProcessReconcile(ctx, resource) } // Reconcile this copy of the resource and then write back any status // updates regardless of whether the reconciliation errored out. reconcileEvent = do(ctx, resource) if !r.skipStatusUpdates { reconciler.PostProcessReconcile(ctx, resource, original) } case reconciler.DoFinalizeKind: // For finalizing reconcilers, if this resource being marked for deletion // and reconciled cleanly (nil or normal event), remove the finalizer. reconcileEvent = do(ctx, resource) if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { return fmt.Errorf("failed to clear finalizers: %w", err) } case reconciler.DoObserveKind: // Observe any changes to this resource, since we are not the leader. reconcileEvent = do(ctx, resource) } // Synchronize the status. switch { case r.skipStatusUpdates: // This reconciler implementation is configured to skip resource updates. // This may mean this reconciler does not observe spec, but reconciles external changes. case equality.Semantic.DeepEqual(original.Status, resource.Status): // If we didn't change anything then don't call updateStatus. // This is important because the copy we loaded from the injectionInformer's // cache may be stale and we don't want to overwrite a prior update // to status with this stale state. case !s.isLeader: // High-availability reconcilers may have many replicas watching the resource, but only // the elected leader is expected to write modifications. logger.Warn("Saw status changes when we aren't the leader!") default: if err = r.updateStatus(ctx, logger, original, resource); err != nil { logger.Warnw("Failed to update resource status", zap.Error(err)) r.Recorder.Eventf(resource, v1.EventTypeWarning, "UpdateFailed", "Failed to update status for %q: %v", resource.Name, err) return err } } // Report the reconciler event, if any. if reconcileEvent != nil { var event *reconciler.ReconcilerEvent if reconciler.EventAs(reconcileEvent, &event) { logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) r.Recorder.Event(resource, event.EventType, event.Reason, event.Error()) // the event was wrapped inside an error, consider the reconciliation as failed if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { return reconcileEvent } return nil } if controller.IsSkipKey(reconcileEvent) { // This is a wrapped error, don't emit an event. } else if ok, _ := controller.IsRequeueKey(reconcileEvent); ok { // This is a wrapped error, don't emit an event. } else { logger.Errorw("Returned an error", zap.Error(reconcileEvent)) r.Recorder.Event(resource, v1.EventTypeWarning, "InternalError", reconcileEvent.Error()) } return reconcileEvent } return nil } func (r *reconcilerImpl) updateStatus(ctx context.Context, logger *zap.SugaredLogger, existing *v1alpha1.ClusterImagePolicy, desired *v1alpha1.ClusterImagePolicy) error { existing = existing.DeepCopy() return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. if attempts > 0 { getter := r.Client.PolicyV1alpha1().ClusterImagePolicies() existing, err = getter.Get(ctx, desired.Name, metav1.GetOptions{}) if err != nil { return err } } // If there's nothing to update, just return. if equality.Semantic.DeepEqual(existing.Status, desired.Status) { return nil } if logger.Desugar().Core().Enabled(zapcore.DebugLevel) { if diff, err := kmp.SafeDiff(existing.Status, desired.Status); err == nil && diff != "" { logger.Debug("Updating status with: ", diff) } } existing.Status = desired.Status updater := r.Client.PolicyV1alpha1().ClusterImagePolicies() _, err = updater.UpdateStatus(ctx, existing, metav1.UpdateOptions{}) return err }) } // updateFinalizersFiltered will update the Finalizers of the resource. // TODO: this method could be generic and sync all finalizers. For now it only // updates defaultFinalizerName or its override. func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1alpha1.ClusterImagePolicy, desiredFinalizers sets.String) (*v1alpha1.ClusterImagePolicy, error) { // Don't modify the informers copy. existing := resource.DeepCopy() var finalizers []string // If there's nothing to update, just return. existingFinalizers := sets.NewString(existing.Finalizers...) if desiredFinalizers.Has(r.finalizerName) { if existingFinalizers.Has(r.finalizerName) { // Nothing to do. return resource, nil } // Add the finalizer. finalizers = append(existing.Finalizers, r.finalizerName) } else { if !existingFinalizers.Has(r.finalizerName) { // Nothing to do. return resource, nil } // Remove the finalizer. existingFinalizers.Delete(r.finalizerName) finalizers = existingFinalizers.List() } mergePatch := map[string]interface{}{ "metadata": map[string]interface{}{ "finalizers": finalizers, "resourceVersion": existing.ResourceVersion, }, } patch, err := json.Marshal(mergePatch) if err != nil { return resource, err } patcher := r.Client.PolicyV1alpha1().ClusterImagePolicies() resourceName := resource.Name updated, err := patcher.Patch(ctx, resourceName, types.MergePatchType, patch, metav1.PatchOptions{}) if err != nil { r.Recorder.Eventf(existing, v1.EventTypeWarning, "FinalizerUpdateFailed", "Failed to update finalizers for %q: %v", resourceName, err) } else { r.Recorder.Eventf(updated, v1.EventTypeNormal, "FinalizerUpdate", "Updated %q finalizers", resource.GetName()) } return updated, err } func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1alpha1.ClusterImagePolicy) (*v1alpha1.ClusterImagePolicy, error) { if _, ok := r.reconciler.(Finalizer); !ok { return resource, nil } finalizers := sets.NewString(resource.Finalizers...) // If this resource is not being deleted, mark the finalizer. if resource.GetDeletionTimestamp().IsZero() { finalizers.Insert(r.finalizerName) } // Synchronize the finalizers filtered by r.finalizerName. return r.updateFinalizersFiltered(ctx, resource, finalizers) } func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1alpha1.ClusterImagePolicy, reconcileEvent reconciler.Event) (*v1alpha1.ClusterImagePolicy, error) { if _, ok := r.reconciler.(Finalizer); !ok { return resource, nil } if resource.GetDeletionTimestamp().IsZero() { return resource, nil } finalizers := sets.NewString(resource.Finalizers...) if reconcileEvent != nil { var event *reconciler.ReconcilerEvent if reconciler.EventAs(reconcileEvent, &event) { if event.EventType == v1.EventTypeNormal { finalizers.Delete(r.finalizerName) } } } else { finalizers.Delete(r.finalizerName) } // Synchronize the finalizers filtered by r.finalizerName. return r.updateFinalizersFiltered(ctx, resource, finalizers) } ================================================ FILE: pkg/client/injection/reconciler/policy/v1alpha1/clusterimagepolicy/state.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package clusterimagepolicy import ( fmt "fmt" v1alpha1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" types "k8s.io/apimachinery/pkg/types" cache "k8s.io/client-go/tools/cache" reconciler "knative.dev/pkg/reconciler" ) // state is used to track the state of a reconciler in a single run. type state struct { // key is the original reconciliation key from the queue. key string // namespace is the namespace split from the reconciliation key. namespace string // name is the name split from the reconciliation key. name string // reconciler is the reconciler. reconciler Interface // roi is the read only interface cast of the reconciler. roi ReadOnlyInterface // isROI (Read Only Interface) the reconciler only observes reconciliation. isROI bool // isLeader the instance of the reconciler is the elected leader. isLeader bool } func newState(key string, r *reconcilerImpl) (*state, error) { // Convert the namespace/name string into a distinct namespace and name. namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { return nil, fmt.Errorf("invalid resource key: %s", key) } roi, isROI := r.reconciler.(ReadOnlyInterface) isLeader := r.IsLeaderFor(types.NamespacedName{ Namespace: namespace, Name: name, }) return &state{ key: key, namespace: namespace, name: name, reconciler: r.reconciler, roi: roi, isROI: isROI, isLeader: isLeader, }, nil } // isNotLeaderNorObserver checks to see if this reconciler with the current // state is enabled to do any work or not. // isNotLeaderNorObserver returns true when there is no work possible for the // reconciler. func (s *state) isNotLeaderNorObserver() bool { if !s.isLeader && !s.isROI { // If we are not the leader, and we don't implement the ReadOnly // interface, then take a fast-path out. return true } return false } func (s *state) reconcileMethodFor(o *v1alpha1.ClusterImagePolicy) (string, doReconcile) { if o.GetDeletionTimestamp().IsZero() { if s.isLeader { return reconciler.DoReconcileKind, s.reconciler.ReconcileKind } else if s.isROI { return reconciler.DoObserveKind, s.roi.ObserveKind } } else if fin, ok := s.reconciler.(Finalizer); s.isLeader && ok { return reconciler.DoFinalizeKind, fin.FinalizeKind } return "unknown", nil } ================================================ FILE: pkg/client/injection/reconciler/policy/v1alpha1/trustroot/controller.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package trustroot import ( context "context" fmt "fmt" reflect "reflect" strings "strings" versionedscheme "github.com/sigstore/policy-controller/pkg/client/clientset/versioned/scheme" client "github.com/sigstore/policy-controller/pkg/client/injection/client" trustroot "github.com/sigstore/policy-controller/pkg/client/injection/informers/policy/v1alpha1/trustroot" zap "go.uber.org/zap" corev1 "k8s.io/api/core/v1" labels "k8s.io/apimachinery/pkg/labels" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" scheme "k8s.io/client-go/kubernetes/scheme" v1 "k8s.io/client-go/kubernetes/typed/core/v1" record "k8s.io/client-go/tools/record" kubeclient "knative.dev/pkg/client/injection/kube/client" controller "knative.dev/pkg/controller" logging "knative.dev/pkg/logging" logkey "knative.dev/pkg/logging/logkey" reconciler "knative.dev/pkg/reconciler" ) const ( defaultControllerAgentName = "trustroot-controller" defaultFinalizerName = "trustroots.policy.sigstore.dev" ) // NewImpl returns a controller.Impl that handles queuing and feeding work from // the queue through an implementation of controller.Reconciler, delegating to // the provided Interface and optional Finalizer methods. OptionsFn is used to return // controller.ControllerOptions to be used by the internal reconciler. func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { logger := logging.FromContext(ctx) // Check the options function input. It should be 0 or 1. if len(optionsFns) > 1 { logger.Fatal("Up to one options function is supported, found: ", len(optionsFns)) } trustrootInformer := trustroot.Get(ctx) lister := trustrootInformer.Lister() var promoteFilterFunc func(obj interface{}) bool var promoteFunc = func(bkt reconciler.Bucket) {} rec := &reconcilerImpl{ LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { // Signal promotion event promoteFunc(bkt) all, err := lister.List(labels.Everything()) if err != nil { return err } for _, elt := range all { if promoteFilterFunc != nil { if ok := promoteFilterFunc(elt); !ok { continue } } enq(bkt, types.NamespacedName{ Namespace: elt.GetNamespace(), Name: elt.GetName(), }) } return nil }, }, Client: client.Get(ctx), Lister: lister, reconciler: r, finalizerName: defaultFinalizerName, } ctrType := reflect.TypeOf(r).Elem() ctrTypeName := fmt.Sprintf("%s.%s", ctrType.PkgPath(), ctrType.Name()) ctrTypeName = strings.ReplaceAll(ctrTypeName, "/", ".") logger = logger.With( zap.String(logkey.ControllerType, ctrTypeName), zap.String(logkey.Kind, "policy.sigstore.dev.TrustRoot"), ) impl := controller.NewContext(ctx, rec, controller.ControllerOptions{WorkQueueName: ctrTypeName, Logger: logger}) agentName := defaultControllerAgentName // Pass impl to the options. Save any optional results. for _, fn := range optionsFns { opts := fn(impl) if opts.ConfigStore != nil { rec.configStore = opts.ConfigStore } if opts.FinalizerName != "" { rec.finalizerName = opts.FinalizerName } if opts.AgentName != "" { agentName = opts.AgentName } if opts.SkipStatusUpdates { rec.skipStatusUpdates = true } if opts.DemoteFunc != nil { rec.DemoteFunc = opts.DemoteFunc } if opts.PromoteFilterFunc != nil { promoteFilterFunc = opts.PromoteFilterFunc } if opts.PromoteFunc != nil { promoteFunc = opts.PromoteFunc } } rec.Recorder = createRecorder(ctx, agentName) return impl } func createRecorder(ctx context.Context, agentName string) record.EventRecorder { logger := logging.FromContext(ctx) recorder := controller.GetEventRecorder(ctx) if recorder == nil { // Create event broadcaster logger.Debug("Creating event broadcaster") eventBroadcaster := record.NewBroadcaster() watches := []watch.Interface{ eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), eventBroadcaster.StartRecordingToSink( &v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}), } recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) go func() { <-ctx.Done() for _, w := range watches { w.Stop() } }() } return recorder } func init() { versionedscheme.AddToScheme(scheme.Scheme) } ================================================ FILE: pkg/client/injection/reconciler/policy/v1alpha1/trustroot/reconciler.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package trustroot import ( context "context" json "encoding/json" fmt "fmt" v1alpha1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" versioned "github.com/sigstore/policy-controller/pkg/client/clientset/versioned" policyv1alpha1 "github.com/sigstore/policy-controller/pkg/client/listers/policy/v1alpha1" zap "go.uber.org/zap" "go.uber.org/zap/zapcore" v1 "k8s.io/api/core/v1" equality "k8s.io/apimachinery/pkg/api/equality" errors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" labels "k8s.io/apimachinery/pkg/labels" types "k8s.io/apimachinery/pkg/types" sets "k8s.io/apimachinery/pkg/util/sets" record "k8s.io/client-go/tools/record" controller "knative.dev/pkg/controller" kmp "knative.dev/pkg/kmp" logging "knative.dev/pkg/logging" reconciler "knative.dev/pkg/reconciler" ) // Interface defines the strongly typed interfaces to be implemented by a // controller reconciling v1alpha1.TrustRoot. type Interface interface { // ReconcileKind implements custom logic to reconcile v1alpha1.TrustRoot. Any changes // to the objects .Status or .Finalizers will be propagated to the stored // object. It is recommended that implementors do not call any update calls // for the Kind inside of ReconcileKind, it is the responsibility of the calling // controller to propagate those properties. The resource passed to ReconcileKind // will always have an empty deletion timestamp. ReconcileKind(ctx context.Context, o *v1alpha1.TrustRoot) reconciler.Event } // Finalizer defines the strongly typed interfaces to be implemented by a // controller finalizing v1alpha1.TrustRoot. type Finalizer interface { // FinalizeKind implements custom logic to finalize v1alpha1.TrustRoot. Any changes // to the objects .Status or .Finalizers will be ignored. Returning a nil or // Normal type reconciler.Event will allow the finalizer to be deleted on // the resource. The resource passed to FinalizeKind will always have a set // deletion timestamp. FinalizeKind(ctx context.Context, o *v1alpha1.TrustRoot) reconciler.Event } // ReadOnlyInterface defines the strongly typed interfaces to be implemented by a // controller reconciling v1alpha1.TrustRoot if they want to process resources for which // they are not the leader. type ReadOnlyInterface interface { // ObserveKind implements logic to observe v1alpha1.TrustRoot. // This method should not write to the API. ObserveKind(ctx context.Context, o *v1alpha1.TrustRoot) reconciler.Event } type doReconcile func(ctx context.Context, o *v1alpha1.TrustRoot) reconciler.Event // reconcilerImpl implements controller.Reconciler for v1alpha1.TrustRoot resources. type reconcilerImpl struct { // LeaderAwareFuncs is inlined to help us implement reconciler.LeaderAware. reconciler.LeaderAwareFuncs // Client is used to write back status updates. Client versioned.Interface // Listers index properties about resources. Lister policyv1alpha1.TrustRootLister // Recorder is an event recorder for recording Event resources to the // Kubernetes API. Recorder record.EventRecorder // configStore allows for decorating a context with config maps. // +optional configStore reconciler.ConfigStore // reconciler is the implementation of the business logic of the resource. reconciler Interface // finalizerName is the name of the finalizer to reconcile. finalizerName string // skipStatusUpdates configures whether or not this reconciler automatically updates // the status of the reconciled resource. skipStatusUpdates bool } // Check that our Reconciler implements controller.Reconciler. var _ controller.Reconciler = (*reconcilerImpl)(nil) // Check that our generated Reconciler is always LeaderAware. var _ reconciler.LeaderAware = (*reconcilerImpl)(nil) func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister policyv1alpha1.TrustRootLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { // Check the options function input. It should be 0 or 1. if len(options) > 1 { logger.Fatal("Up to one options struct is supported, found: ", len(options)) } // Fail fast when users inadvertently implement the other LeaderAware interface. // For the typed reconcilers, Promote shouldn't take any arguments. if _, ok := r.(reconciler.LeaderAware); ok { logger.Fatalf("%T implements the incorrect LeaderAware interface. Promote() should not take an argument as genreconciler handles the enqueuing automatically.", r) } rec := &reconcilerImpl{ LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { all, err := lister.List(labels.Everything()) if err != nil { return err } for _, elt := range all { // TODO: Consider letting users specify a filter in options. enq(bkt, types.NamespacedName{ Namespace: elt.GetNamespace(), Name: elt.GetName(), }) } return nil }, }, Client: client, Lister: lister, Recorder: recorder, reconciler: r, finalizerName: defaultFinalizerName, } for _, opts := range options { if opts.ConfigStore != nil { rec.configStore = opts.ConfigStore } if opts.FinalizerName != "" { rec.finalizerName = opts.FinalizerName } if opts.SkipStatusUpdates { rec.skipStatusUpdates = true } if opts.DemoteFunc != nil { rec.DemoteFunc = opts.DemoteFunc } } return rec } // Reconcile implements controller.Reconciler func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { logger := logging.FromContext(ctx) // Initialize the reconciler state. This will convert the namespace/name // string into a distinct namespace and name, determine if this instance of // the reconciler is the leader, and any additional interfaces implemented // by the reconciler. Returns an error is the resource key is invalid. s, err := newState(key, r) if err != nil { logger.Error("Invalid resource key: ", key) return nil } // If we are not the leader, and we don't implement either ReadOnly // observer interfaces, then take a fast-path out. if s.isNotLeaderNorObserver() { return controller.NewSkipKey(key) } // If configStore is set, attach the frozen configuration to the context. if r.configStore != nil { ctx = r.configStore.ToContext(ctx) } // Add the recorder to context. ctx = controller.WithEventRecorder(ctx, r.Recorder) // Get the resource with this namespace/name. getter := r.Lister original, err := getter.Get(s.name) if errors.IsNotFound(err) { // The resource may no longer exist, in which case we stop processing and call // the ObserveDeletion handler if appropriate. logger.Debugf("Resource %q no longer exists", key) if del, ok := r.reconciler.(reconciler.OnDeletionInterface); ok { return del.ObserveDeletion(ctx, types.NamespacedName{ Namespace: s.namespace, Name: s.name, }) } return nil } else if err != nil { return err } // Don't modify the informers copy. resource := original.DeepCopy() var reconcileEvent reconciler.Event name, do := s.reconcileMethodFor(resource) // Append the target method to the logger. logger = logger.With(zap.String("targetMethod", name)) switch name { case reconciler.DoReconcileKind: // Set and update the finalizer on resource if r.reconciler // implements Finalizer. if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { return fmt.Errorf("failed to set finalizers: %w", err) } if !r.skipStatusUpdates { reconciler.PreProcessReconcile(ctx, resource) } // Reconcile this copy of the resource and then write back any status // updates regardless of whether the reconciliation errored out. reconcileEvent = do(ctx, resource) if !r.skipStatusUpdates { reconciler.PostProcessReconcile(ctx, resource, original) } case reconciler.DoFinalizeKind: // For finalizing reconcilers, if this resource being marked for deletion // and reconciled cleanly (nil or normal event), remove the finalizer. reconcileEvent = do(ctx, resource) if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { return fmt.Errorf("failed to clear finalizers: %w", err) } case reconciler.DoObserveKind: // Observe any changes to this resource, since we are not the leader. reconcileEvent = do(ctx, resource) } // Synchronize the status. switch { case r.skipStatusUpdates: // This reconciler implementation is configured to skip resource updates. // This may mean this reconciler does not observe spec, but reconciles external changes. case equality.Semantic.DeepEqual(original.Status, resource.Status): // If we didn't change anything then don't call updateStatus. // This is important because the copy we loaded from the injectionInformer's // cache may be stale and we don't want to overwrite a prior update // to status with this stale state. case !s.isLeader: // High-availability reconcilers may have many replicas watching the resource, but only // the elected leader is expected to write modifications. logger.Warn("Saw status changes when we aren't the leader!") default: if err = r.updateStatus(ctx, logger, original, resource); err != nil { logger.Warnw("Failed to update resource status", zap.Error(err)) r.Recorder.Eventf(resource, v1.EventTypeWarning, "UpdateFailed", "Failed to update status for %q: %v", resource.Name, err) return err } } // Report the reconciler event, if any. if reconcileEvent != nil { var event *reconciler.ReconcilerEvent if reconciler.EventAs(reconcileEvent, &event) { logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) r.Recorder.Event(resource, event.EventType, event.Reason, event.Error()) // the event was wrapped inside an error, consider the reconciliation as failed if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { return reconcileEvent } return nil } if controller.IsSkipKey(reconcileEvent) { // This is a wrapped error, don't emit an event. } else if ok, _ := controller.IsRequeueKey(reconcileEvent); ok { // This is a wrapped error, don't emit an event. } else { logger.Errorw("Returned an error", zap.Error(reconcileEvent)) r.Recorder.Event(resource, v1.EventTypeWarning, "InternalError", reconcileEvent.Error()) } return reconcileEvent } return nil } func (r *reconcilerImpl) updateStatus(ctx context.Context, logger *zap.SugaredLogger, existing *v1alpha1.TrustRoot, desired *v1alpha1.TrustRoot) error { existing = existing.DeepCopy() return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. if attempts > 0 { getter := r.Client.PolicyV1alpha1().TrustRoots() existing, err = getter.Get(ctx, desired.Name, metav1.GetOptions{}) if err != nil { return err } } // If there's nothing to update, just return. if equality.Semantic.DeepEqual(existing.Status, desired.Status) { return nil } if logger.Desugar().Core().Enabled(zapcore.DebugLevel) { if diff, err := kmp.SafeDiff(existing.Status, desired.Status); err == nil && diff != "" { logger.Debug("Updating status with: ", diff) } } existing.Status = desired.Status updater := r.Client.PolicyV1alpha1().TrustRoots() _, err = updater.UpdateStatus(ctx, existing, metav1.UpdateOptions{}) return err }) } // updateFinalizersFiltered will update the Finalizers of the resource. // TODO: this method could be generic and sync all finalizers. For now it only // updates defaultFinalizerName or its override. func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1alpha1.TrustRoot, desiredFinalizers sets.String) (*v1alpha1.TrustRoot, error) { // Don't modify the informers copy. existing := resource.DeepCopy() var finalizers []string // If there's nothing to update, just return. existingFinalizers := sets.NewString(existing.Finalizers...) if desiredFinalizers.Has(r.finalizerName) { if existingFinalizers.Has(r.finalizerName) { // Nothing to do. return resource, nil } // Add the finalizer. finalizers = append(existing.Finalizers, r.finalizerName) } else { if !existingFinalizers.Has(r.finalizerName) { // Nothing to do. return resource, nil } // Remove the finalizer. existingFinalizers.Delete(r.finalizerName) finalizers = existingFinalizers.List() } mergePatch := map[string]interface{}{ "metadata": map[string]interface{}{ "finalizers": finalizers, "resourceVersion": existing.ResourceVersion, }, } patch, err := json.Marshal(mergePatch) if err != nil { return resource, err } patcher := r.Client.PolicyV1alpha1().TrustRoots() resourceName := resource.Name updated, err := patcher.Patch(ctx, resourceName, types.MergePatchType, patch, metav1.PatchOptions{}) if err != nil { r.Recorder.Eventf(existing, v1.EventTypeWarning, "FinalizerUpdateFailed", "Failed to update finalizers for %q: %v", resourceName, err) } else { r.Recorder.Eventf(updated, v1.EventTypeNormal, "FinalizerUpdate", "Updated %q finalizers", resource.GetName()) } return updated, err } func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1alpha1.TrustRoot) (*v1alpha1.TrustRoot, error) { if _, ok := r.reconciler.(Finalizer); !ok { return resource, nil } finalizers := sets.NewString(resource.Finalizers...) // If this resource is not being deleted, mark the finalizer. if resource.GetDeletionTimestamp().IsZero() { finalizers.Insert(r.finalizerName) } // Synchronize the finalizers filtered by r.finalizerName. return r.updateFinalizersFiltered(ctx, resource, finalizers) } func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1alpha1.TrustRoot, reconcileEvent reconciler.Event) (*v1alpha1.TrustRoot, error) { if _, ok := r.reconciler.(Finalizer); !ok { return resource, nil } if resource.GetDeletionTimestamp().IsZero() { return resource, nil } finalizers := sets.NewString(resource.Finalizers...) if reconcileEvent != nil { var event *reconciler.ReconcilerEvent if reconciler.EventAs(reconcileEvent, &event) { if event.EventType == v1.EventTypeNormal { finalizers.Delete(r.finalizerName) } } } else { finalizers.Delete(r.finalizerName) } // Synchronize the finalizers filtered by r.finalizerName. return r.updateFinalizersFiltered(ctx, resource, finalizers) } ================================================ FILE: pkg/client/injection/reconciler/policy/v1alpha1/trustroot/state.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package trustroot import ( fmt "fmt" v1alpha1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" types "k8s.io/apimachinery/pkg/types" cache "k8s.io/client-go/tools/cache" reconciler "knative.dev/pkg/reconciler" ) // state is used to track the state of a reconciler in a single run. type state struct { // key is the original reconciliation key from the queue. key string // namespace is the namespace split from the reconciliation key. namespace string // name is the name split from the reconciliation key. name string // reconciler is the reconciler. reconciler Interface // roi is the read only interface cast of the reconciler. roi ReadOnlyInterface // isROI (Read Only Interface) the reconciler only observes reconciliation. isROI bool // isLeader the instance of the reconciler is the elected leader. isLeader bool } func newState(key string, r *reconcilerImpl) (*state, error) { // Convert the namespace/name string into a distinct namespace and name. namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { return nil, fmt.Errorf("invalid resource key: %s", key) } roi, isROI := r.reconciler.(ReadOnlyInterface) isLeader := r.IsLeaderFor(types.NamespacedName{ Namespace: namespace, Name: name, }) return &state{ key: key, namespace: namespace, name: name, reconciler: r.reconciler, roi: roi, isROI: isROI, isLeader: isLeader, }, nil } // isNotLeaderNorObserver checks to see if this reconciler with the current // state is enabled to do any work or not. // isNotLeaderNorObserver returns true when there is no work possible for the // reconciler. func (s *state) isNotLeaderNorObserver() bool { if !s.isLeader && !s.isROI { // If we are not the leader, and we don't implement the ReadOnly // interface, then take a fast-path out. return true } return false } func (s *state) reconcileMethodFor(o *v1alpha1.TrustRoot) (string, doReconcile) { if o.GetDeletionTimestamp().IsZero() { if s.isLeader { return reconciler.DoReconcileKind, s.reconciler.ReconcileKind } else if s.isROI { return reconciler.DoObserveKind, s.roi.ObserveKind } } else if fin, ok := s.reconciler.(Finalizer); s.isLeader && ok { return reconciler.DoFinalizeKind, fin.FinalizeKind } return "unknown", nil } ================================================ FILE: pkg/client/injection/reconciler/policy/v1beta1/clusterimagepolicy/controller.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package clusterimagepolicy import ( context "context" fmt "fmt" reflect "reflect" strings "strings" versionedscheme "github.com/sigstore/policy-controller/pkg/client/clientset/versioned/scheme" client "github.com/sigstore/policy-controller/pkg/client/injection/client" clusterimagepolicy "github.com/sigstore/policy-controller/pkg/client/injection/informers/policy/v1beta1/clusterimagepolicy" zap "go.uber.org/zap" corev1 "k8s.io/api/core/v1" labels "k8s.io/apimachinery/pkg/labels" types "k8s.io/apimachinery/pkg/types" watch "k8s.io/apimachinery/pkg/watch" scheme "k8s.io/client-go/kubernetes/scheme" v1 "k8s.io/client-go/kubernetes/typed/core/v1" record "k8s.io/client-go/tools/record" kubeclient "knative.dev/pkg/client/injection/kube/client" controller "knative.dev/pkg/controller" logging "knative.dev/pkg/logging" logkey "knative.dev/pkg/logging/logkey" reconciler "knative.dev/pkg/reconciler" ) const ( defaultControllerAgentName = "clusterimagepolicy-controller" defaultFinalizerName = "clusterimagepolicies.policy.sigstore.dev" ) // NewImpl returns a controller.Impl that handles queuing and feeding work from // the queue through an implementation of controller.Reconciler, delegating to // the provided Interface and optional Finalizer methods. OptionsFn is used to return // controller.ControllerOptions to be used by the internal reconciler. func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { logger := logging.FromContext(ctx) // Check the options function input. It should be 0 or 1. if len(optionsFns) > 1 { logger.Fatal("Up to one options function is supported, found: ", len(optionsFns)) } clusterimagepolicyInformer := clusterimagepolicy.Get(ctx) lister := clusterimagepolicyInformer.Lister() var promoteFilterFunc func(obj interface{}) bool var promoteFunc = func(bkt reconciler.Bucket) {} rec := &reconcilerImpl{ LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { // Signal promotion event promoteFunc(bkt) all, err := lister.List(labels.Everything()) if err != nil { return err } for _, elt := range all { if promoteFilterFunc != nil { if ok := promoteFilterFunc(elt); !ok { continue } } enq(bkt, types.NamespacedName{ Namespace: elt.GetNamespace(), Name: elt.GetName(), }) } return nil }, }, Client: client.Get(ctx), Lister: lister, reconciler: r, finalizerName: defaultFinalizerName, } ctrType := reflect.TypeOf(r).Elem() ctrTypeName := fmt.Sprintf("%s.%s", ctrType.PkgPath(), ctrType.Name()) ctrTypeName = strings.ReplaceAll(ctrTypeName, "/", ".") logger = logger.With( zap.String(logkey.ControllerType, ctrTypeName), zap.String(logkey.Kind, "policy.sigstore.dev.ClusterImagePolicy"), ) impl := controller.NewContext(ctx, rec, controller.ControllerOptions{WorkQueueName: ctrTypeName, Logger: logger}) agentName := defaultControllerAgentName // Pass impl to the options. Save any optional results. for _, fn := range optionsFns { opts := fn(impl) if opts.ConfigStore != nil { rec.configStore = opts.ConfigStore } if opts.FinalizerName != "" { rec.finalizerName = opts.FinalizerName } if opts.AgentName != "" { agentName = opts.AgentName } if opts.SkipStatusUpdates { rec.skipStatusUpdates = true } if opts.DemoteFunc != nil { rec.DemoteFunc = opts.DemoteFunc } if opts.PromoteFilterFunc != nil { promoteFilterFunc = opts.PromoteFilterFunc } if opts.PromoteFunc != nil { promoteFunc = opts.PromoteFunc } } rec.Recorder = createRecorder(ctx, agentName) return impl } func createRecorder(ctx context.Context, agentName string) record.EventRecorder { logger := logging.FromContext(ctx) recorder := controller.GetEventRecorder(ctx) if recorder == nil { // Create event broadcaster logger.Debug("Creating event broadcaster") eventBroadcaster := record.NewBroadcaster() watches := []watch.Interface{ eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), eventBroadcaster.StartRecordingToSink( &v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}), } recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) go func() { <-ctx.Done() for _, w := range watches { w.Stop() } }() } return recorder } func init() { versionedscheme.AddToScheme(scheme.Scheme) } ================================================ FILE: pkg/client/injection/reconciler/policy/v1beta1/clusterimagepolicy/reconciler.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package clusterimagepolicy import ( context "context" json "encoding/json" fmt "fmt" v1beta1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1beta1" versioned "github.com/sigstore/policy-controller/pkg/client/clientset/versioned" policyv1beta1 "github.com/sigstore/policy-controller/pkg/client/listers/policy/v1beta1" zap "go.uber.org/zap" "go.uber.org/zap/zapcore" v1 "k8s.io/api/core/v1" equality "k8s.io/apimachinery/pkg/api/equality" errors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" labels "k8s.io/apimachinery/pkg/labels" types "k8s.io/apimachinery/pkg/types" sets "k8s.io/apimachinery/pkg/util/sets" record "k8s.io/client-go/tools/record" controller "knative.dev/pkg/controller" kmp "knative.dev/pkg/kmp" logging "knative.dev/pkg/logging" reconciler "knative.dev/pkg/reconciler" ) // Interface defines the strongly typed interfaces to be implemented by a // controller reconciling v1beta1.ClusterImagePolicy. type Interface interface { // ReconcileKind implements custom logic to reconcile v1beta1.ClusterImagePolicy. Any changes // to the objects .Status or .Finalizers will be propagated to the stored // object. It is recommended that implementors do not call any update calls // for the Kind inside of ReconcileKind, it is the responsibility of the calling // controller to propagate those properties. The resource passed to ReconcileKind // will always have an empty deletion timestamp. ReconcileKind(ctx context.Context, o *v1beta1.ClusterImagePolicy) reconciler.Event } // Finalizer defines the strongly typed interfaces to be implemented by a // controller finalizing v1beta1.ClusterImagePolicy. type Finalizer interface { // FinalizeKind implements custom logic to finalize v1beta1.ClusterImagePolicy. Any changes // to the objects .Status or .Finalizers will be ignored. Returning a nil or // Normal type reconciler.Event will allow the finalizer to be deleted on // the resource. The resource passed to FinalizeKind will always have a set // deletion timestamp. FinalizeKind(ctx context.Context, o *v1beta1.ClusterImagePolicy) reconciler.Event } // ReadOnlyInterface defines the strongly typed interfaces to be implemented by a // controller reconciling v1beta1.ClusterImagePolicy if they want to process resources for which // they are not the leader. type ReadOnlyInterface interface { // ObserveKind implements logic to observe v1beta1.ClusterImagePolicy. // This method should not write to the API. ObserveKind(ctx context.Context, o *v1beta1.ClusterImagePolicy) reconciler.Event } type doReconcile func(ctx context.Context, o *v1beta1.ClusterImagePolicy) reconciler.Event // reconcilerImpl implements controller.Reconciler for v1beta1.ClusterImagePolicy resources. type reconcilerImpl struct { // LeaderAwareFuncs is inlined to help us implement reconciler.LeaderAware. reconciler.LeaderAwareFuncs // Client is used to write back status updates. Client versioned.Interface // Listers index properties about resources. Lister policyv1beta1.ClusterImagePolicyLister // Recorder is an event recorder for recording Event resources to the // Kubernetes API. Recorder record.EventRecorder // configStore allows for decorating a context with config maps. // +optional configStore reconciler.ConfigStore // reconciler is the implementation of the business logic of the resource. reconciler Interface // finalizerName is the name of the finalizer to reconcile. finalizerName string // skipStatusUpdates configures whether or not this reconciler automatically updates // the status of the reconciled resource. skipStatusUpdates bool } // Check that our Reconciler implements controller.Reconciler. var _ controller.Reconciler = (*reconcilerImpl)(nil) // Check that our generated Reconciler is always LeaderAware. var _ reconciler.LeaderAware = (*reconcilerImpl)(nil) func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister policyv1beta1.ClusterImagePolicyLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { // Check the options function input. It should be 0 or 1. if len(options) > 1 { logger.Fatal("Up to one options struct is supported, found: ", len(options)) } // Fail fast when users inadvertently implement the other LeaderAware interface. // For the typed reconcilers, Promote shouldn't take any arguments. if _, ok := r.(reconciler.LeaderAware); ok { logger.Fatalf("%T implements the incorrect LeaderAware interface. Promote() should not take an argument as genreconciler handles the enqueuing automatically.", r) } rec := &reconcilerImpl{ LeaderAwareFuncs: reconciler.LeaderAwareFuncs{ PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error { all, err := lister.List(labels.Everything()) if err != nil { return err } for _, elt := range all { // TODO: Consider letting users specify a filter in options. enq(bkt, types.NamespacedName{ Namespace: elt.GetNamespace(), Name: elt.GetName(), }) } return nil }, }, Client: client, Lister: lister, Recorder: recorder, reconciler: r, finalizerName: defaultFinalizerName, } for _, opts := range options { if opts.ConfigStore != nil { rec.configStore = opts.ConfigStore } if opts.FinalizerName != "" { rec.finalizerName = opts.FinalizerName } if opts.SkipStatusUpdates { rec.skipStatusUpdates = true } if opts.DemoteFunc != nil { rec.DemoteFunc = opts.DemoteFunc } } return rec } // Reconcile implements controller.Reconciler func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { logger := logging.FromContext(ctx) // Initialize the reconciler state. This will convert the namespace/name // string into a distinct namespace and name, determine if this instance of // the reconciler is the leader, and any additional interfaces implemented // by the reconciler. Returns an error is the resource key is invalid. s, err := newState(key, r) if err != nil { logger.Error("Invalid resource key: ", key) return nil } // If we are not the leader, and we don't implement either ReadOnly // observer interfaces, then take a fast-path out. if s.isNotLeaderNorObserver() { return controller.NewSkipKey(key) } // If configStore is set, attach the frozen configuration to the context. if r.configStore != nil { ctx = r.configStore.ToContext(ctx) } // Add the recorder to context. ctx = controller.WithEventRecorder(ctx, r.Recorder) // Get the resource with this namespace/name. getter := r.Lister original, err := getter.Get(s.name) if errors.IsNotFound(err) { // The resource may no longer exist, in which case we stop processing and call // the ObserveDeletion handler if appropriate. logger.Debugf("Resource %q no longer exists", key) if del, ok := r.reconciler.(reconciler.OnDeletionInterface); ok { return del.ObserveDeletion(ctx, types.NamespacedName{ Namespace: s.namespace, Name: s.name, }) } return nil } else if err != nil { return err } // Don't modify the informers copy. resource := original.DeepCopy() var reconcileEvent reconciler.Event name, do := s.reconcileMethodFor(resource) // Append the target method to the logger. logger = logger.With(zap.String("targetMethod", name)) switch name { case reconciler.DoReconcileKind: // Set and update the finalizer on resource if r.reconciler // implements Finalizer. if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { return fmt.Errorf("failed to set finalizers: %w", err) } if !r.skipStatusUpdates { reconciler.PreProcessReconcile(ctx, resource) } // Reconcile this copy of the resource and then write back any status // updates regardless of whether the reconciliation errored out. reconcileEvent = do(ctx, resource) if !r.skipStatusUpdates { reconciler.PostProcessReconcile(ctx, resource, original) } case reconciler.DoFinalizeKind: // For finalizing reconcilers, if this resource being marked for deletion // and reconciled cleanly (nil or normal event), remove the finalizer. reconcileEvent = do(ctx, resource) if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { return fmt.Errorf("failed to clear finalizers: %w", err) } case reconciler.DoObserveKind: // Observe any changes to this resource, since we are not the leader. reconcileEvent = do(ctx, resource) } // Synchronize the status. switch { case r.skipStatusUpdates: // This reconciler implementation is configured to skip resource updates. // This may mean this reconciler does not observe spec, but reconciles external changes. case equality.Semantic.DeepEqual(original.Status, resource.Status): // If we didn't change anything then don't call updateStatus. // This is important because the copy we loaded from the injectionInformer's // cache may be stale and we don't want to overwrite a prior update // to status with this stale state. case !s.isLeader: // High-availability reconcilers may have many replicas watching the resource, but only // the elected leader is expected to write modifications. logger.Warn("Saw status changes when we aren't the leader!") default: if err = r.updateStatus(ctx, logger, original, resource); err != nil { logger.Warnw("Failed to update resource status", zap.Error(err)) r.Recorder.Eventf(resource, v1.EventTypeWarning, "UpdateFailed", "Failed to update status for %q: %v", resource.Name, err) return err } } // Report the reconciler event, if any. if reconcileEvent != nil { var event *reconciler.ReconcilerEvent if reconciler.EventAs(reconcileEvent, &event) { logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) r.Recorder.Event(resource, event.EventType, event.Reason, event.Error()) // the event was wrapped inside an error, consider the reconciliation as failed if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { return reconcileEvent } return nil } if controller.IsSkipKey(reconcileEvent) { // This is a wrapped error, don't emit an event. } else if ok, _ := controller.IsRequeueKey(reconcileEvent); ok { // This is a wrapped error, don't emit an event. } else { logger.Errorw("Returned an error", zap.Error(reconcileEvent)) r.Recorder.Event(resource, v1.EventTypeWarning, "InternalError", reconcileEvent.Error()) } return reconcileEvent } return nil } func (r *reconcilerImpl) updateStatus(ctx context.Context, logger *zap.SugaredLogger, existing *v1beta1.ClusterImagePolicy, desired *v1beta1.ClusterImagePolicy) error { existing = existing.DeepCopy() return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. if attempts > 0 { getter := r.Client.PolicyV1beta1().ClusterImagePolicies() existing, err = getter.Get(ctx, desired.Name, metav1.GetOptions{}) if err != nil { return err } } // If there's nothing to update, just return. if equality.Semantic.DeepEqual(existing.Status, desired.Status) { return nil } if logger.Desugar().Core().Enabled(zapcore.DebugLevel) { if diff, err := kmp.SafeDiff(existing.Status, desired.Status); err == nil && diff != "" { logger.Debug("Updating status with: ", diff) } } existing.Status = desired.Status updater := r.Client.PolicyV1beta1().ClusterImagePolicies() _, err = updater.UpdateStatus(ctx, existing, metav1.UpdateOptions{}) return err }) } // updateFinalizersFiltered will update the Finalizers of the resource. // TODO: this method could be generic and sync all finalizers. For now it only // updates defaultFinalizerName or its override. func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1beta1.ClusterImagePolicy, desiredFinalizers sets.String) (*v1beta1.ClusterImagePolicy, error) { // Don't modify the informers copy. existing := resource.DeepCopy() var finalizers []string // If there's nothing to update, just return. existingFinalizers := sets.NewString(existing.Finalizers...) if desiredFinalizers.Has(r.finalizerName) { if existingFinalizers.Has(r.finalizerName) { // Nothing to do. return resource, nil } // Add the finalizer. finalizers = append(existing.Finalizers, r.finalizerName) } else { if !existingFinalizers.Has(r.finalizerName) { // Nothing to do. return resource, nil } // Remove the finalizer. existingFinalizers.Delete(r.finalizerName) finalizers = existingFinalizers.List() } mergePatch := map[string]interface{}{ "metadata": map[string]interface{}{ "finalizers": finalizers, "resourceVersion": existing.ResourceVersion, }, } patch, err := json.Marshal(mergePatch) if err != nil { return resource, err } patcher := r.Client.PolicyV1beta1().ClusterImagePolicies() resourceName := resource.Name updated, err := patcher.Patch(ctx, resourceName, types.MergePatchType, patch, metav1.PatchOptions{}) if err != nil { r.Recorder.Eventf(existing, v1.EventTypeWarning, "FinalizerUpdateFailed", "Failed to update finalizers for %q: %v", resourceName, err) } else { r.Recorder.Eventf(updated, v1.EventTypeNormal, "FinalizerUpdate", "Updated %q finalizers", resource.GetName()) } return updated, err } func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1beta1.ClusterImagePolicy) (*v1beta1.ClusterImagePolicy, error) { if _, ok := r.reconciler.(Finalizer); !ok { return resource, nil } finalizers := sets.NewString(resource.Finalizers...) // If this resource is not being deleted, mark the finalizer. if resource.GetDeletionTimestamp().IsZero() { finalizers.Insert(r.finalizerName) } // Synchronize the finalizers filtered by r.finalizerName. return r.updateFinalizersFiltered(ctx, resource, finalizers) } func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1beta1.ClusterImagePolicy, reconcileEvent reconciler.Event) (*v1beta1.ClusterImagePolicy, error) { if _, ok := r.reconciler.(Finalizer); !ok { return resource, nil } if resource.GetDeletionTimestamp().IsZero() { return resource, nil } finalizers := sets.NewString(resource.Finalizers...) if reconcileEvent != nil { var event *reconciler.ReconcilerEvent if reconciler.EventAs(reconcileEvent, &event) { if event.EventType == v1.EventTypeNormal { finalizers.Delete(r.finalizerName) } } } else { finalizers.Delete(r.finalizerName) } // Synchronize the finalizers filtered by r.finalizerName. return r.updateFinalizersFiltered(ctx, resource, finalizers) } ================================================ FILE: pkg/client/injection/reconciler/policy/v1beta1/clusterimagepolicy/state.go ================================================ // 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. // Code generated by injection-gen. DO NOT EDIT. package clusterimagepolicy import ( fmt "fmt" v1beta1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1beta1" types "k8s.io/apimachinery/pkg/types" cache "k8s.io/client-go/tools/cache" reconciler "knative.dev/pkg/reconciler" ) // state is used to track the state of a reconciler in a single run. type state struct { // key is the original reconciliation key from the queue. key string // namespace is the namespace split from the reconciliation key. namespace string // name is the name split from the reconciliation key. name string // reconciler is the reconciler. reconciler Interface // roi is the read only interface cast of the reconciler. roi ReadOnlyInterface // isROI (Read Only Interface) the reconciler only observes reconciliation. isROI bool // isLeader the instance of the reconciler is the elected leader. isLeader bool } func newState(key string, r *reconcilerImpl) (*state, error) { // Convert the namespace/name string into a distinct namespace and name. namespace, name, err := cache.SplitMetaNamespaceKey(key) if err != nil { return nil, fmt.Errorf("invalid resource key: %s", key) } roi, isROI := r.reconciler.(ReadOnlyInterface) isLeader := r.IsLeaderFor(types.NamespacedName{ Namespace: namespace, Name: name, }) return &state{ key: key, namespace: namespace, name: name, reconciler: r.reconciler, roi: roi, isROI: isROI, isLeader: isLeader, }, nil } // isNotLeaderNorObserver checks to see if this reconciler with the current // state is enabled to do any work or not. // isNotLeaderNorObserver returns true when there is no work possible for the // reconciler. func (s *state) isNotLeaderNorObserver() bool { if !s.isLeader && !s.isROI { // If we are not the leader, and we don't implement the ReadOnly // interface, then take a fast-path out. return true } return false } func (s *state) reconcileMethodFor(o *v1beta1.ClusterImagePolicy) (string, doReconcile) { if o.GetDeletionTimestamp().IsZero() { if s.isLeader { return reconciler.DoReconcileKind, s.reconciler.ReconcileKind } else if s.isROI { return reconciler.DoObserveKind, s.roi.ObserveKind } } else if fin, ok := s.reconciler.(Finalizer); s.isLeader && ok { return reconciler.DoFinalizeKind, fin.FinalizeKind } return "unknown", nil } ================================================ FILE: pkg/client/listers/policy/v1alpha1/clusterimagepolicy.go ================================================ // 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. // Code generated by lister-gen. DO NOT EDIT. package v1alpha1 import ( v1alpha1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/tools/cache" ) // ClusterImagePolicyLister helps list ClusterImagePolicies. // All objects returned here must be treated as read-only. type ClusterImagePolicyLister interface { // List lists all ClusterImagePolicies in the indexer. // Objects returned here must be treated as read-only. List(selector labels.Selector) (ret []*v1alpha1.ClusterImagePolicy, err error) // Get retrieves the ClusterImagePolicy from the index for a given name. // Objects returned here must be treated as read-only. Get(name string) (*v1alpha1.ClusterImagePolicy, error) ClusterImagePolicyListerExpansion } // clusterImagePolicyLister implements the ClusterImagePolicyLister interface. type clusterImagePolicyLister struct { indexer cache.Indexer } // NewClusterImagePolicyLister returns a new ClusterImagePolicyLister. func NewClusterImagePolicyLister(indexer cache.Indexer) ClusterImagePolicyLister { return &clusterImagePolicyLister{indexer: indexer} } // List lists all ClusterImagePolicies in the indexer. func (s *clusterImagePolicyLister) List(selector labels.Selector) (ret []*v1alpha1.ClusterImagePolicy, err error) { err = cache.ListAll(s.indexer, selector, func(m interface{}) { ret = append(ret, m.(*v1alpha1.ClusterImagePolicy)) }) return ret, err } // Get retrieves the ClusterImagePolicy from the index for a given name. func (s *clusterImagePolicyLister) Get(name string) (*v1alpha1.ClusterImagePolicy, error) { obj, exists, err := s.indexer.GetByKey(name) if err != nil { return nil, err } if !exists { return nil, errors.NewNotFound(v1alpha1.Resource("clusterimagepolicy"), name) } return obj.(*v1alpha1.ClusterImagePolicy), nil } ================================================ FILE: pkg/client/listers/policy/v1alpha1/expansion_generated.go ================================================ // 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. // Code generated by lister-gen. DO NOT EDIT. package v1alpha1 // ClusterImagePolicyListerExpansion allows custom methods to be added to // ClusterImagePolicyLister. type ClusterImagePolicyListerExpansion interface{} // TrustRootListerExpansion allows custom methods to be added to // TrustRootLister. type TrustRootListerExpansion interface{} ================================================ FILE: pkg/client/listers/policy/v1alpha1/trustroot.go ================================================ // 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. // Code generated by lister-gen. DO NOT EDIT. package v1alpha1 import ( v1alpha1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/tools/cache" ) // TrustRootLister helps list TrustRoots. // All objects returned here must be treated as read-only. type TrustRootLister interface { // List lists all TrustRoots in the indexer. // Objects returned here must be treated as read-only. List(selector labels.Selector) (ret []*v1alpha1.TrustRoot, err error) // Get retrieves the TrustRoot from the index for a given name. // Objects returned here must be treated as read-only. Get(name string) (*v1alpha1.TrustRoot, error) TrustRootListerExpansion } // trustRootLister implements the TrustRootLister interface. type trustRootLister struct { indexer cache.Indexer } // NewTrustRootLister returns a new TrustRootLister. func NewTrustRootLister(indexer cache.Indexer) TrustRootLister { return &trustRootLister{indexer: indexer} } // List lists all TrustRoots in the indexer. func (s *trustRootLister) List(selector labels.Selector) (ret []*v1alpha1.TrustRoot, err error) { err = cache.ListAll(s.indexer, selector, func(m interface{}) { ret = append(ret, m.(*v1alpha1.TrustRoot)) }) return ret, err } // Get retrieves the TrustRoot from the index for a given name. func (s *trustRootLister) Get(name string) (*v1alpha1.TrustRoot, error) { obj, exists, err := s.indexer.GetByKey(name) if err != nil { return nil, err } if !exists { return nil, errors.NewNotFound(v1alpha1.Resource("trustroot"), name) } return obj.(*v1alpha1.TrustRoot), nil } ================================================ FILE: pkg/client/listers/policy/v1beta1/clusterimagepolicy.go ================================================ // 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. // Code generated by lister-gen. DO NOT EDIT. package v1beta1 import ( v1beta1 "github.com/sigstore/policy-controller/pkg/apis/policy/v1beta1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" "k8s.io/client-go/tools/cache" ) // ClusterImagePolicyLister helps list ClusterImagePolicies. // All objects returned here must be treated as read-only. type ClusterImagePolicyLister interface { // List lists all ClusterImagePolicies in the indexer. // Objects returned here must be treated as read-only. List(selector labels.Selector) (ret []*v1beta1.ClusterImagePolicy, err error) // Get retrieves the ClusterImagePolicy from the index for a given name. // Objects returned here must be treated as read-only. Get(name string) (*v1beta1.ClusterImagePolicy, error) ClusterImagePolicyListerExpansion } // clusterImagePolicyLister implements the ClusterImagePolicyLister interface. type clusterImagePolicyLister struct { indexer cache.Indexer } // NewClusterImagePolicyLister returns a new ClusterImagePolicyLister. func NewClusterImagePolicyLister(indexer cache.Indexer) ClusterImagePolicyLister { return &clusterImagePolicyLister{indexer: indexer} } // List lists all ClusterImagePolicies in the indexer. func (s *clusterImagePolicyLister) List(selector labels.Selector) (ret []*v1beta1.ClusterImagePolicy, err error) { err = cache.ListAll(s.indexer, selector, func(m interface{}) { ret = append(ret, m.(*v1beta1.ClusterImagePolicy)) }) return ret, err } // Get retrieves the ClusterImagePolicy from the index for a given name. func (s *clusterImagePolicyLister) Get(name string) (*v1beta1.ClusterImagePolicy, error) { obj, exists, err := s.indexer.GetByKey(name) if err != nil { return nil, err } if !exists { return nil, errors.NewNotFound(v1beta1.Resource("clusterimagepolicy"), name) } return obj.(*v1beta1.ClusterImagePolicy), nil } ================================================ FILE: pkg/client/listers/policy/v1beta1/expansion_generated.go ================================================ // 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. // Code generated by lister-gen. DO NOT EDIT. package v1beta1 // ClusterImagePolicyListerExpansion allows custom methods to be added to // ClusterImagePolicyLister. type ClusterImagePolicyListerExpansion interface{} ================================================ FILE: pkg/config/store.go ================================================ // // 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. package config import ( "context" "strconv" corev1 "k8s.io/api/core/v1" "knative.dev/pkg/configmap" ) type cfgKey struct{} const ( // PolicyControllerConfigName is the name of the configmap used to configure // policy-controller. PolicyControllerConfigName = "config-policy-controller" //nolint: gosec // Specifies that if an image is not found to match any policy, it should // be rejected. DenyAll = "deny" // Specifies that if an image is not found to match any policy, it should // be allowed. AllowAll = "allow" WarnAll = "warn" NoMatchPolicyKey = "no-match-policy" FailOnEmptyAuthorities = "fail-on-empty-authorities" EnableOCI11 = "enable-oci11" ) // PolicyControllerConfig controls the behaviour of policy-controller that needs // to be more flexible than requiring a controller restart. Some examples are // controlling behaviour for what to do if no matching policies are found. // Point is that these apply to the whole controller instead of specific CIP // policies that apply only to matching images. type PolicyControllerConfig struct { // NoMatchPolicy says what do in the case where an image does not match // any policy. NoMatchPolicy string `json:"no-match-policy"` // FailOnEmptyAuthorities configures the validating webhook to allow creating CIP without a list authorities FailOnEmptyAuthorities bool `json:"fail-on-empty-authorities"` // EnableOCI11 enables experimental OCI 1.1 referrers API for attestation discovery EnableOCI11 bool `json:"enable-oci11"` } func NewPolicyControllerConfigFromMap(data map[string]string) (*PolicyControllerConfig, error) { ret := &PolicyControllerConfig{NoMatchPolicy: "deny", FailOnEmptyAuthorities: true} switch data[NoMatchPolicyKey] { case DenyAll: ret.NoMatchPolicy = DenyAll case AllowAll: ret.NoMatchPolicy = AllowAll case WarnAll: ret.NoMatchPolicy = WarnAll default: ret.NoMatchPolicy = DenyAll } if val, ok := data[FailOnEmptyAuthorities]; ok { var err error ret.FailOnEmptyAuthorities, err = strconv.ParseBool(val) if err != nil { return ret, err } } if val, ok := data[EnableOCI11]; ok { var err error ret.EnableOCI11, err = strconv.ParseBool(val) if err != nil { return ret, err } } return ret, nil } func NewPolicyControllerConfigFromConfigMap(config *corev1.ConfigMap) (*PolicyControllerConfig, error) { return NewPolicyControllerConfigFromMap(config.Data) } // FromContext extracts a PolicyControllerConfig from the provided context. func FromContext(ctx context.Context) *PolicyControllerConfig { x, ok := ctx.Value(cfgKey{}).(*PolicyControllerConfig) if ok { return x } return nil } // FromContextOrDefaults is like FromContext, but when no // PolicyControllerConfig is attached, it returns a PolicyControllerConfig // populated with the defaults for each of the fields. func FromContextOrDefaults(ctx context.Context) *PolicyControllerConfig { if cfg := FromContext(ctx); cfg != nil { return cfg } return &PolicyControllerConfig{ NoMatchPolicy: DenyAll, FailOnEmptyAuthorities: true, EnableOCI11: false, } } // ToContext attaches the provided PolicyControllerConfig to the provided // context, returning the new context with the Config attached. func ToContext(ctx context.Context, c *PolicyControllerConfig) context.Context { return context.WithValue(ctx, cfgKey{}, c) } // Store is a typed wrapper around configmap.Untyped store to handle our configmaps. // +k8s:deepcopy-gen=false type Store struct { *configmap.UntypedStore } // NewStore creates a new store of Configs and optionally calls functions when ConfigMaps are updated. func NewStore(logger configmap.Logger, onAfterStore ...func(name string, value interface{})) *Store { store := &Store{ UntypedStore: configmap.NewUntypedStore( PolicyControllerConfigName, logger, configmap.Constructors{ PolicyControllerConfigName: NewPolicyControllerConfigFromConfigMap, }, onAfterStore..., ), } return store } // ToContext attaches the current PolicyControllerConfig state to the provided // context. func (s *Store) ToContext(ctx context.Context) context.Context { return ToContext(ctx, s.Load()) } // Load creates a PolicyControllerConfig from the current config state of the // Store. func (s *Store) Load() *PolicyControllerConfig { return s.UntypedLoad(PolicyControllerConfigName).(*PolicyControllerConfig) } ================================================ FILE: pkg/config/store_test.go ================================================ // 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. package config import ( "context" "testing" "github.com/google/go-cmp/cmp" logtesting "knative.dev/pkg/logging/testing" . "knative.dev/pkg/configmap/testing" ) type testData struct { noMatchPolicy string failOnEmptyAuthorities bool enableOCI11 bool } var testfiles = map[string]testData{ "allow-all": {noMatchPolicy: AllowAll, failOnEmptyAuthorities: true, enableOCI11: false}, "deny-all-explicit": {noMatchPolicy: DenyAll, failOnEmptyAuthorities: true, enableOCI11: false}, "warn-all": {noMatchPolicy: WarnAll, failOnEmptyAuthorities: true, enableOCI11: false}, "deny-all-default": {noMatchPolicy: DenyAll, failOnEmptyAuthorities: true, enableOCI11: false}, "allow-empty-authorities": {noMatchPolicy: DenyAll, failOnEmptyAuthorities: false, enableOCI11: false}, } func TestStoreLoadWithContext(t *testing.T) { store := NewStore(logtesting.TestLogger(t)) for file, want := range testfiles { _, policyControllerConfig := ConfigMapsFromTestFile(t, file) store.OnConfigChanged(policyControllerConfig) config := FromContextOrDefaults(store.ToContext(context.Background())) t.Run("policy-controller-config-test-"+file, func(t *testing.T) { expected, _ := NewPolicyControllerConfigFromConfigMap(policyControllerConfig) if diff := cmp.Diff(want.noMatchPolicy, expected.NoMatchPolicy); diff != "" { t.Error("Unexpected defaults config (-want, +got):", diff) } if diff := cmp.Diff(want.failOnEmptyAuthorities, expected.FailOnEmptyAuthorities); diff != "" { t.Error("Unexpected defaults config (-want, +got):", diff) } if diff := cmp.Diff(want.enableOCI11, expected.EnableOCI11); diff != "" { t.Error("Unexpected EnableOCI11 config (-want, +got):", diff) } if diff := cmp.Diff(expected, config); diff != "" { t.Error("Unexpected defaults config (-want, +got):", diff) } }) } } func TestStoreLoadWithContextOrDefaults(t *testing.T) { for file := range testfiles { policyControllerConfig := ConfigMapFromTestFile(t, file) config := FromContextOrDefaults(context.Background()) t.Run("policy-controller-config-tests-"+file, func(t *testing.T) { expected, _ := NewPolicyControllerConfigFromConfigMap(policyControllerConfig) // These all should have the default, because we don't parse the // _example in these tests. if diff := cmp.Diff(DenyAll, expected.NoMatchPolicy); diff != "" { t.Error("Unexpected defaults config (-want, +got):", diff) } if diff := cmp.Diff(expected, config); diff != "" { t.Error("Unexpected defaults config (-want, +got):", diff) } }) } } func TestEnableOCI11Config(t *testing.T) { tests := []struct { name string data map[string]string wantOCI11 bool wantErr bool }{ { name: "enable-oci11 true", data: map[string]string{"enable-oci11": "true"}, wantOCI11: true, wantErr: false, }, { name: "enable-oci11 false", data: map[string]string{"enable-oci11": "false"}, wantOCI11: false, wantErr: false, }, { name: "enable-oci11 not set (default false)", data: map[string]string{}, wantOCI11: false, wantErr: false, }, { name: "enable-oci11 invalid value", data: map[string]string{"enable-oci11": "not-a-boolean"}, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cfg, err := NewPolicyControllerConfigFromMap(tt.data) if (err != nil) != tt.wantErr { t.Errorf("NewPolicyControllerConfigFromMap() error = %v, wantErr %v", err, tt.wantErr) return } if !tt.wantErr { if cfg.EnableOCI11 != tt.wantOCI11 { t.Errorf("EnableOCI11 = %v, want %v", cfg.EnableOCI11, tt.wantOCI11) } } }) } } func TestFromContextOrDefaultsWithOCI11(t *testing.T) { // Test default returns EnableOCI11 = false cfg := FromContextOrDefaults(context.Background()) if cfg.EnableOCI11 != false { t.Errorf("Default EnableOCI11 = %v, want false", cfg.EnableOCI11) } // Test with EnableOCI11 = true in context customCfg := &PolicyControllerConfig{ NoMatchPolicy: DenyAll, FailOnEmptyAuthorities: true, EnableOCI11: true, } ctx := ToContext(context.Background(), customCfg) cfg = FromContextOrDefaults(ctx) if cfg.EnableOCI11 != true { t.Errorf("Context EnableOCI11 = %v, want true", cfg.EnableOCI11) } } ================================================ FILE: pkg/config/testdata/allow-all.yaml ================================================ # 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. apiVersion: v1 kind: ConfigMap metadata: name: config-policy-controller namespace: cosign-system labels: policy.sigstore.dev/release: devel data: _example: | no-match-policy: allow ================================================ FILE: pkg/config/testdata/allow-empty-authorities.yaml ================================================ # 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. apiVersion: v1 kind: ConfigMap metadata: name: config-policy-controller namespace: cosign-system labels: policy.sigstore.dev/release: devel data: _example: | no-match-policy: deny fail-on-empty-authorities: false ================================================ FILE: pkg/config/testdata/deny-all-default.yaml ================================================ # 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. apiVersion: v1 kind: ConfigMap metadata: name: config-policy-controller namespace: cosign-system labels: policy.sigstore.dev/release: devel data: _example: | some-other-key: somethingelse ================================================ FILE: pkg/config/testdata/deny-all-explicit.yaml ================================================ # 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. apiVersion: v1 kind: ConfigMap metadata: name: config-policy-controller namespace: cosign-system labels: policy.sigstore.dev/release: devel data: _example: | no-match-policy: deny ================================================ FILE: pkg/config/testdata/enable-oci11-invalid.yaml ================================================ # Copyright 2025 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. apiVersion: v1 kind: ConfigMap metadata: name: config-policy-controller namespace: cosign-system data: enable-oci11: "not-a-boolean" ================================================ FILE: pkg/config/testdata/enable-oci11.yaml ================================================ # Copyright 2025 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. apiVersion: v1 kind: ConfigMap metadata: name: config-policy-controller namespace: cosign-system data: enable-oci11: "true" ================================================ FILE: pkg/config/testdata/warn-all.yaml ================================================ # 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. apiVersion: v1 kind: ConfigMap metadata: name: config-policy-controller namespace: cosign-system labels: policy.sigstore.dev/release: devel data: _example: | no-match-policy: warn ================================================ FILE: pkg/policy/README.md ================================================ # Integrating Policy Verification The goal of this package is to make it easy for downstream tools to incorporate the verification capabilities of `ClusterImagePolicy` in other contexts where OCI artifacts are consumed. The most straightforward example of this is to enable OCI build tooling to incorporate policies over the base images on top of which an application image is built (e.g. `ko`, `kaniko`). However, this can be used by other tooling that stores artifacts in OCI registries to verify those as well, examples of this could include the way Buildpacks v3 and Crossplane store elements in OCI registries. ## Configuration Verification is configured via `policy.Verification`: ```golang type Verification struct { // NoMatchPolicy specifies the behavior when a base image doesn't match any // of the listed policies. It allows the values: allow, deny, and warn. NoMatchPolicy string `yaml:"no-match-policy,omitempty"` // Policies specifies a collection of policies to use to cover the base // images used as part of evaluation. See "policy" below for usage. // Policies can be nil so that we can distinguish between an explicitly // specified empty list and when policies is unspecified. Policies *[]Source `yaml:"policies,omitempty"` } ``` `NoMatchPolicy` controls the behavior when an image reference is passed that does not match any of the configured policies. `Policies` can be specified via three possible sources: ```golang // Source contains a set of options for specifying policies. Exactly // one of the fields may be specified for each Source entry. type Source struct { // Data is a collection of one or more ClusterImagePolicy resources. Data string `yaml:"data,omitempty"` // Path is a path to a file containing one or more ClusterImagePolicy // resources. // TODO(mattmoor): Make this support taking a directory similar to kubectl. // TODO(mattmoor): How do we want to handle something like -R? Perhaps we // don't and encourage folks to list each directory individually? Path string `yaml:"path,omitempty"` // URL links to a file containing one or more ClusterImagePolicy resources. URL string `yaml:"url,omitempty"` } ``` ### With `spf13/viper` Many tools leverage `spf13/viper` for configuration, and `policy.Verification` may be used in conjunction with viper via: ```golang vfy := policy.Verification{} if err := v.UnmarshalKey("verification", &vfy); err != nil { ... } ``` This allows a section of the viper config: ```yaml verification: noMatchPolicy: deny policies: - data: ... # Inline policies - url: ... # URL to policies ... ``` ## Compilation The `policy.Verification` can be compiled into a `policy.Verifier` using `policy.Compile`, which also takes a `context.Context` and a function that controls how warnings are surfaced: ```golang verifier, err := policy.Compile(ctx, verification, func(s string, i ...interface{}) { // Handle warnings your own way! }) if err != nil { ... } ``` The compilation process will surface compilation warnings via the supplied function and return any errors resolving or compiling the policies immediately. ## Verification With a compiled `policy.Verifier` many image references can be verified against the compiled policies by invoking `Verify`: ```golang // Verifier is the interface for checking that a given image digest satisfies // the policies backing this interface. type Verifier interface { // Verify checks that the provided reference satisfies the backing policies. Verify(context.Context, name.Reference, authn.Keychain) error } ``` ================================================ FILE: pkg/policy/parse.go ================================================ // Copyright 2023 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. package policy import ( "context" "encoding/json" "fmt" "strings" "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" "github.com/sigstore/policy-controller/pkg/apis/policy/v1beta1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" "knative.dev/pkg/apis" "sigs.k8s.io/yaml" ) // Parse decodes a provided YAML document containing zero or more objects into // a collection of unstructured.Unstructured objects. func Parse(_ context.Context, document string) ([]*unstructured.Unstructured, error) { docs := strings.Split(document, "\n---\n") objs := make([]*unstructured.Unstructured, 0, len(docs)) for i, doc := range docs { doc = strings.TrimSpace(doc) if doc == "" { continue } var obj unstructured.Unstructured if err := yaml.Unmarshal([]byte(doc), &obj); err != nil { return nil, fmt.Errorf("decoding object[%d]: %w", i, err) } if obj.GetAPIVersion() == "" { return nil, apis.ErrMissingField("apiVersion").ViaIndex(i) } if obj.GetName() == "" { return nil, apis.ErrMissingField("metadata.name").ViaIndex(i) } objs = append(objs, &obj) } return objs, nil } // ParseClusterImagePolicies returns ClusterImagePolicy objects found in the // policy document. func ParseClusterImagePolicies(ctx context.Context, document string) (cips []*v1alpha1.ClusterImagePolicy, warns error, err error) { if warns, err = Validate(ctx, document); err != nil { return nil, warns, err } ol, err := Parse(ctx, document) if err != nil { // "Validate" above calls "Parse", so this is unreachable. return nil, warns, err } cips = make([]*v1alpha1.ClusterImagePolicy, 0, len(ol)) for _, obj := range ol { gv, err := schema.ParseGroupVersion(obj.GetAPIVersion()) if err != nil { // Practically speaking unstructured.Unstructured won't let this happen. return nil, warns, fmt.Errorf("error parsing apiVersion of: %w", err) } cip := &v1alpha1.ClusterImagePolicy{} switch gv.WithKind(obj.GetKind()) { case v1beta1.SchemeGroupVersion.WithKind("ClusterImagePolicy"): v1b1 := &v1beta1.ClusterImagePolicy{} if err := convert(obj, v1b1); err != nil { return nil, warns, err } if err := cip.ConvertFrom(ctx, v1b1); err != nil { return nil, warns, err } case v1alpha1.SchemeGroupVersion.WithKind("ClusterImagePolicy"): // This is allowed, but we should convert things. if err := convert(obj, cip); err != nil { return nil, warns, err } default: continue } cips = append(cips, cip) } return cips, warns, nil } func convert(from interface{}, to interface{}) error { bs, err := json.Marshal(from) if err != nil { return fmt.Errorf("Marshal() = %w", err) } if err := json.Unmarshal(bs, to); err != nil { return fmt.Errorf("Unmarshal() = %w", err) } return nil } ================================================ FILE: pkg/policy/parse_test.go ================================================ // Copyright 2023 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. package policy import ( "context" "errors" "testing" "github.com/google/go-cmp/cmp" "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "knative.dev/pkg/apis" ) func TestParse(t *testing.T) { tests := []struct { name string doc string want []*unstructured.Unstructured wantErr error }{{ name: "good single object", doc: ` apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: blah spec: {} `, want: []*unstructured.Unstructured{{ Object: map[string]interface{}{ "apiVersion": "policy.sigstore.dev/v1beta1", "kind": "ClusterImagePolicy", "metadata": map[string]interface{}{ "name": "blah", }, "spec": map[string]interface{}{}, }, }}, }, { name: "good multi-object", doc: ` apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: blah spec: {} --- --- apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: foo spec: {} --- --- apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: bar spec: {} `, want: []*unstructured.Unstructured{{ Object: map[string]interface{}{ "apiVersion": "policy.sigstore.dev/v1beta1", "kind": "ClusterImagePolicy", "metadata": map[string]interface{}{ "name": "blah", }, "spec": map[string]interface{}{}, }, }, { Object: map[string]interface{}{ "apiVersion": "policy.sigstore.dev/v1beta1", "kind": "ClusterImagePolicy", "metadata": map[string]interface{}{ "name": "foo", }, "spec": map[string]interface{}{}, }, }, { Object: map[string]interface{}{ "apiVersion": "policy.sigstore.dev/v1beta1", "kind": "ClusterImagePolicy", "metadata": map[string]interface{}{ "name": "bar", }, "spec": map[string]interface{}{}, }, }}, }, { name: "bad missing apiVersion", doc: ` apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: blah spec: {} --- # Missing: apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: foo spec: {} --- apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: bar spec: {} `, wantErr: apis.ErrMissingField("[1].apiVersion"), }, { name: "bad missing kind", doc: ` apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: blah spec: {} --- apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: foo spec: {} --- apiVersion: policy.sigstore.dev/v1beta1 # Missing: kind: ClusterImagePolicy metadata: name: bar spec: {} `, wantErr: errors.New(`decoding object[2]: error unmarshaling JSON: while decoding JSON: Object 'Kind' is missing in '{"apiVersion":"policy.sigstore.dev/v1beta1","metadata":{"name":"bar"},"spec":{}}'`), }, { name: "bad missing apiVersion", doc: ` apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: # Missing: name: blah sp dec: {} --- apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: foo spec: {} --- apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: bar spec: {} `, wantErr: apis.ErrMissingField("[0].metadata.name"), }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { got, gotErr := Parse(context.Background(), test.doc) switch { case (gotErr != nil) != (test.wantErr != nil): t.Fatalf("Parse() = %v, wanted %v", gotErr, test.wantErr) case gotErr != nil && gotErr.Error() != test.wantErr.Error(): t.Fatalf("Parse() = %v, wanted %v", gotErr, test.wantErr) case gotErr != nil: return // This was an error test. } if diff := cmp.Diff(got, test.want); diff != "" { t.Errorf("Parse (-got, +want) = %s", diff) } }) } } func TestParseCIP(t *testing.T) { tests := []struct { name string doc string want []*v1alpha1.ClusterImagePolicy wantErr error }{{ name: "good alpha object", doc: ` apiVersion: policy.sigstore.dev/v1alpha1 kind: ClusterImagePolicy metadata: name: blah spec: images: - glob: '**' authorities: - static: action: pass `, want: []*v1alpha1.ClusterImagePolicy{{ TypeMeta: v1.TypeMeta{ APIVersion: "policy.sigstore.dev/v1alpha1", Kind: "ClusterImagePolicy", }, ObjectMeta: v1.ObjectMeta{ Name: "blah", }, Spec: v1alpha1.ClusterImagePolicySpec{ Images: []v1alpha1.ImagePattern{{ Glob: "**", }}, Authorities: []v1alpha1.Authority{{ Static: &v1alpha1.StaticRef{ Action: "pass", }, }}, }, }}, }, { name: "good beta object", doc: ` apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: blah spec: images: - glob: '**' authorities: - static: action: pass `, want: []*v1alpha1.ClusterImagePolicy{{ // TODO(mattmoor): We should be setting TypeMeta when converting. // TypeMeta: v1.TypeMeta{ // APIVersion: "policy.sigstore.dev/v1alpha1", // Kind: "ClusterImagePolicy", // }, ObjectMeta: v1.ObjectMeta{ Name: "blah", }, Spec: v1alpha1.ClusterImagePolicySpec{ Images: []v1alpha1.ImagePattern{{ Glob: "**", }}, Authorities: []v1alpha1.Authority{{ Static: &v1alpha1.StaticRef{ Action: "pass", }, }}, }, }}, }, { name: "early validation failure", doc: ` apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: blah spec: bad: field `, wantErr: errors.New(`unable to unmarshal: json: unknown field "bad"`), }, { name: "non CIP resource", doc: ` apiVersion: v1 kind: Secret metadata: name: blah namespace: cosign-system stringData: key: value `, want: []*v1alpha1.ClusterImagePolicy{}, }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { got, _, gotErr := ParseClusterImagePolicies(context.Background(), test.doc) switch { case (gotErr != nil) != (test.wantErr != nil): t.Fatalf("Parse() = %v, wanted %v", gotErr, test.wantErr) case gotErr != nil && gotErr.Error() != test.wantErr.Error(): t.Fatalf("Parse() = %v, wanted %v", gotErr, test.wantErr) case gotErr != nil: return // This was an error test. } if diff := cmp.Diff(got, test.want); diff != "" { t.Errorf("Parse (-got, +want) = %s", diff) } }) } } ================================================ FILE: pkg/policy/policy.go ================================================ // Copyright 2023 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. package policy import ( "context" "fmt" "io" "net/http" "os" "k8s.io/apimachinery/pkg/util/sets" "knative.dev/pkg/apis" ) type Verification struct { // NoMatchPolicy specifies the behavior when a base image doesn't match any // of the listed policies. It allows the values: allow, deny, and warn. NoMatchPolicy string `yaml:"no-match-policy,omitempty"` // Policies specifies a set of Sources for fetching policies to use to cover // images used as part of evaluation. For more information about what each // Source supports, see its usage. // Policies can be nil so that we can distinguish between an explicitly // specified empty list and when policies is unspecified. Policies *[]Source `yaml:"policies,omitempty"` } // Source contains a set of options for specifying policies. Exactly // one of the fields may be specified for each Source entry. type Source struct { // Data is a collection of one or more ClusterImagePolicy resources. Data string `yaml:"data,omitempty"` // Path is a path to a file containing one or more ClusterImagePolicy // resources. Path string `yaml:"path,omitempty"` // URL links to a file containing one or more ClusterImagePolicy resources. URL string `yaml:"url,omitempty"` } func (v *Verification) Validate(ctx context.Context) (errs *apis.FieldError) { switch v.NoMatchPolicy { case "allow", "deny", "warn": // Good! case "": errs = errs.Also(apis.ErrMissingField("noMatchPolicy")) default: errs = errs.Also(apis.ErrInvalidValue(v.NoMatchPolicy, "noMatchPolicy")) } if v.Policies == nil { errs = errs.Also(apis.ErrMissingField("policies")) } else { for i, p := range *v.Policies { errs = errs.Also(p.Validate(ctx).ViaFieldIndex("policies", i)) } } return errs } func (pd *Source) Validate(ctx context.Context) *apis.FieldError { // Check that exactly one of the fields is set. set := sets.NewString() if pd.Data != "" { set.Insert("data") } if pd.Path != "" { set.Insert("path") } if pd.URL != "" { set.Insert("url") } // This returns eagerly to avoid confusing `oneof` validation with errors // along multiple paths of the oneof. switch set.Len() { case 0: return apis.ErrMissingOneOf("data", "path", "url") case 1: // What we want. default: // This will be unreachable until we add more than one thing // to our oneof. return apis.ErrMultipleOneOf(set.List()...) } // We know (from the switch above) there is exactly one field name. field, _ := set.PopAny() content, err := pd.fetch(ctx) if err != nil { return &apis.FieldError{ Message: err.Error(), Paths: []string{field}, } } if _, _, err := ParseClusterImagePolicies(ctx, content); err != nil { return apis.ErrInvalidValue(err.Error(), field) } return nil } func (pd *Source) fetch(ctx context.Context) (string, error) { switch { case pd.Data != "": return pd.Data, nil case pd.Path != "": raw, err := os.ReadFile(pd.Path) if err != nil { return "", err } return string(raw), nil case pd.URL != "": req, err := http.NewRequestWithContext(ctx, http.MethodGet, pd.URL, nil) if err != nil { return "", err } resp, err := http.DefaultClient.Do(req) if err != nil { return "", err } defer resp.Body.Close() raw, err := io.ReadAll(resp.Body) if err != nil { return "", err } return string(raw), nil default: // This should never happen for a validated policy. return "", fmt.Errorf("unsupported policy shape: %v", pd) } } ================================================ FILE: pkg/policy/policy_test.go ================================================ // Copyright 2023 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. package policy import ( "context" "errors" "testing" ) const ( // This is an example of what the default ko policy should be // as of 2023/01/03. goodPolicy = ` apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: ko-default-base-image-policy spec: images: - glob: cgr.dev/chainguard/static* authorities: - keyless: url: https://fulcio.sigstore.dev identities: - issuer: https://token.actions.githubusercontent.com subject: https://github.com/chainguard-images/images/.github/workflows/release.yaml@refs/heads/main ctlog: url: https://rekor.sigstore.dev ` badPolicy = ` apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: ko-default-base-image-policy spec: bad: field ` ) func TestVerificationValidate(t *testing.T) { tests := []struct { name string v Verification wantErr error }{{ name: "legacy compatibility settings", v: Verification{ NoMatchPolicy: "allow", Policies: &[]Source{}, }, }, { name: "sample ko default settings", v: Verification{ NoMatchPolicy: "warn", Policies: &[]Source{{ Data: goodPolicy, }}, }, }, { name: "sample strict settings", v: Verification{ NoMatchPolicy: "deny", Policies: &[]Source{{ Data: goodPolicy, }}, }, }, { name: "sample URL settings", v: Verification{ NoMatchPolicy: "deny", Policies: &[]Source{{ URL: "https://raw.githubusercontent.com/sigstore/policy-controller/d6ef1f37c9c634fdb2693c11f8aa91c19e76e7d8/examples/policies/allow-only-pods.yaml", }}, }, }, { name: "sample path settings", v: Verification{ NoMatchPolicy: "deny", Policies: &[]Source{{ Path: "../../examples/policies/allow-only-pods.yaml", }}, }, }, { name: "missing no match policy", v: Verification{ NoMatchPolicy: "", Policies: &[]Source{{ Data: goodPolicy, }}, }, wantErr: errors.New(`missing field(s): noMatchPolicy`), }, { name: "bad no match policy", v: Verification{ NoMatchPolicy: "bad", Policies: &[]Source{{ Data: goodPolicy, }}, }, wantErr: errors.New(`invalid value: bad: noMatchPolicy`), }, { name: "missing policies", v: Verification{ NoMatchPolicy: "warn", }, wantErr: errors.New(`missing field(s): policies`), }, { name: "missing policy data", v: Verification{ NoMatchPolicy: "warn", Policies: &[]Source{{ // NO BODY }}, }, wantErr: errors.New(`expected exactly one, got neither: policies[0].data, policies[0].path, policies[0].url`), }, { name: "bad policy data", v: Verification{ NoMatchPolicy: "warn", Policies: &[]Source{{ Data: badPolicy, }}, }, wantErr: errors.New(`invalid value: unable to unmarshal: json: unknown field "bad": policies[0].data`), }, { name: "bad URL", v: Verification{ NoMatchPolicy: "deny", Policies: &[]Source{{ URL: "bad", }}, }, wantErr: errors.New(`Get "bad": unsupported protocol scheme "": policies[0].url`), }, { name: "bad URL content", v: Verification{ NoMatchPolicy: "deny", Policies: &[]Source{{ URL: "https://raw.githubusercontent.com/sigstore/policy-controller/d6ef1f37c9c634fdb2693c11f8aa91c19e76e7d8/README.md", }}, }, wantErr: errors.New(`invalid value: decoding object[0]: error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type map[string]interface {}: policies[0].url`), }, { name: "both provided", v: Verification{ NoMatchPolicy: "deny", Policies: &[]Source{{ Data: goodPolicy, URL: "https://raw.githubusercontent.com/sigstore/policy-controller/d6ef1f37c9c634fdb2693c11f8aa91c19e76e7d8/examples/policies/allow-only-pods.yaml", }}, }, wantErr: errors.New(`expected exactly one, got both: policies[0].data, policies[0].url`), }, { name: "path not found", v: Verification{ NoMatchPolicy: "deny", Policies: &[]Source{{ Path: "not-found.yaml", }}, }, wantErr: errors.New(`open not-found.yaml: no such file or directory: policies[0].path`), }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { testContext := context.Background() gotErr := test.v.Validate(testContext) if (gotErr != nil) != (test.wantErr != nil) { t.Fatalf("Validate() = %v, wanted %v", gotErr, test.wantErr) } if gotErr != nil && gotErr.Error() != test.wantErr.Error() { t.Fatalf("Validate() = %v, wanted %v", gotErr, test.wantErr) } }) t.Run("compile: "+test.name, func(t *testing.T) { testContext := context.Background() _, gotErr := Compile(testContext, test.v, t.Logf) if (gotErr != nil) != (test.wantErr != nil) { t.Fatalf("Validate() = %v, wanted %v", gotErr, test.wantErr) } if gotErr != nil && gotErr.Error() != test.wantErr.Error() { t.Fatalf("Validate() = %v, wanted %v", gotErr, test.wantErr) } }) } } ================================================ FILE: pkg/policy/validate.go ================================================ // Copyright 2023 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. package policy import ( "bytes" "context" "encoding/json" "errors" "fmt" "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" "github.com/sigstore/policy-controller/pkg/apis/policy/v1beta1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "knative.dev/pkg/apis" ) var ( // ErrEmptyDocument is the error returned when no document body is // specified. ErrEmptyDocument = errors.New("document is required to create policy") // ErrUnknownType is the error returned when a type contained in the policy // is unrecognized. ErrUnknownType = errors.New("unknown type") ) // Validate decodes a provided YAML document containing zero or more objects // and performs limited validation on them, after applying defaulting (to // simulate the mutating webhook running before the validating webhook). func Validate(ctx context.Context, document string) (warns error, err error) { if len(document) == 0 { return nil, ErrEmptyDocument } uol, err := Parse(ctx, document) if err != nil { return nil, err } for i, uo := range uol { switch uo.GroupVersionKind() { case v1beta1.SchemeGroupVersion.WithKind("ClusterImagePolicy"): if warns, err = validate(ctx, uo, &v1beta1.ClusterImagePolicy{}); err != nil { return } case v1alpha1.SchemeGroupVersion.WithKind("ClusterImagePolicy"): if warns, err = validate(ctx, uo, &v1alpha1.ClusterImagePolicy{}); err != nil { return } case corev1.SchemeGroupVersion.WithKind("Secret"): if uo.GetNamespace() != "cosign-system" { return warns, apis.ErrInvalidValue(uo.GetNamespace(), "metadata.namespace").ViaIndex(i) } // Any additional validation worth performing? Should we check the // schema of the secret matches the expectations of cosigned? default: return warns, fmt.Errorf("%w: %v", ErrUnknownType, uo.GroupVersionKind()) } } return warns, nil } type crd interface { apis.Validatable apis.Defaultable } func validate(ctx context.Context, uo *unstructured.Unstructured, v crd) (warns error, err error) { b, err := json.Marshal(uo) if err != nil { return nil, fmt.Errorf("unable to marshal: %w", err) } dec := json.NewDecoder(bytes.NewBuffer(b)) dec.DisallowUnknownFields() if err := dec.Decode(v); err != nil { return nil, fmt.Errorf("unable to unmarshal: %w", err) } // Apply defaulting to simulate the defaulting webhook that runs prior // to validation. v.SetDefaults(ctx) // We can't just return v.Validate(ctx) because of Go's typed nils. // nolint:revive if ve := v.Validate(ctx); ve != nil { // Separate validation warnings from errors so the caller can discern between them. if warnFE := ve.Filter(apis.WarningLevel); warnFE != nil { warns = warnFE } if errorFE := ve.Filter(apis.ErrorLevel); errorFE != nil { err = errorFE } } return } ================================================ FILE: pkg/policy/validate_test.go ================================================ // Copyright 2023 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. package policy import ( "context" "errors" "testing" policycontrollerconfig "github.com/sigstore/policy-controller/pkg/config" "knative.dev/pkg/apis" ) func TestValidate(t *testing.T) { tests := []struct { name string doc string wantWarns error wantErr error allowEmptyAuthorities bool }{{ name: "good single object", doc: ` apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: blah spec: images: - glob: '*' authorities: - keyless: identities: - issuer: https://issuer.example.com subject: foo@example.com url: https://fulcio.sigstore.dev `, wantErr: nil, }, { name: "good CIP and Secret", doc: ` apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: blah spec: images: - glob: '*' authorities: - keyless: identities: - issuer: https://issuer.example.com subject: foo@example.com url: https://fulcio.sigstore.dev --- apiVersion: v1 kind: Secret metadata: name: foo namespace: cosign-system stringData: foo: bar `, wantErr: nil, }, { name: "bad secret namespace", doc: ` apiVersion: v1 kind: Secret metadata: name: foo namespace: something-system stringData: foo: bar `, wantErr: errors.New(`invalid value: something-system: [0].metadata.namespace`), }, { name: "bad image policy", doc: ` apiVersion: policy.sigstore.dev/v1alpha1 kind: ClusterImagePolicy metadata: name: blah spec: images: - glob: '*' authorities: - key: {} `, wantErr: apis.ErrMissingOneOf("data", "kms", "secretref").ViaField("key").ViaFieldIndex("authorities", 0).ViaField("spec"), }, { name: "empty document", doc: ``, wantErr: ErrEmptyDocument, }, { name: "object missing kind", doc: ` apiVersion: policy.sigstore.dev/v1beta1 # Missing: kind: ClusterImagePolicy metadata: name: blah spec: {} `, wantErr: errors.New(`decoding object[0]: error unmarshaling JSON: while decoding JSON: Object 'Kind' is missing in '{"apiVersion":"policy.sigstore.dev/v1beta1","metadata":{"name":"blah"},"spec":{}}'`), }, { name: "unknown field", doc: ` apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: blah spec: asdf: dfsadf `, wantErr: errors.New(`unable to unmarshal: json: unknown field "asdf"`), }, { name: "unknown type", doc: ` apiVersion: unknown.dev/v1 kind: OtherPolicy metadata: name: blah spec: {} `, wantErr: errors.New(`unknown type: unknown.dev/v1, Kind=OtherPolicy`), }, { name: "error - missing field", doc: ` apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: blah spec: images: - glob: '*' authorities: - keyless: url: https://fulcio.sigstore.dev `, wantErr: errors.New("missing field(s): spec.authorities[0].keyless.identities"), }, { name: "admit - missing authorities", doc: ` apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: blah spec: images: - glob: '*' `, wantErr: nil, allowEmptyAuthorities: true, }, { name: "deny - missing authorities", doc: ` apiVersion: policy.sigstore.dev/v1beta1 kind: ClusterImagePolicy metadata: name: blah spec: images: - glob: '*' `, wantErr: errors.New("missing field(s): spec.authorities"), }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { testContext := context.Background() if test.allowEmptyAuthorities { testContext = policycontrollerconfig.ToContext(testContext, &policycontrollerconfig.PolicyControllerConfig{FailOnEmptyAuthorities: false}) } gotWarns, gotErr := Validate(testContext, test.doc) if (gotErr != nil) != (test.wantErr != nil) { t.Fatalf("Validate() = %v, wanted %v", gotErr, test.wantErr) } if (gotWarns != nil) != (test.wantWarns != nil) { t.Fatalf("Validate() = %v, wanted %v", gotWarns, test.wantWarns) } if gotErr != nil && gotErr.Error() != test.wantErr.Error() { t.Fatalf("Validate() = %v, wanted %v", gotErr, test.wantErr) } if gotWarns != nil && gotWarns.Error() != test.wantWarns.Error() { t.Fatalf("Validate() = %v, wanted %v", gotWarns, test.wantWarns) } }) } } ================================================ FILE: pkg/policy/verifier.go ================================================ // Copyright 2023 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. package policy import ( "context" "errors" "fmt" "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/remote" ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" "github.com/sigstore/policy-controller/pkg/apis/config" "github.com/sigstore/policy-controller/pkg/webhook" webhookcip "github.com/sigstore/policy-controller/pkg/webhook/clusterimagepolicy" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/pkg/apis" ) // Verifier is the interface for checking that a given image digest satisfies // the policies backing this interface. type Verifier interface { // Verify checks that the provided reference satisfies the backing policies. // // For policies specifying `match:` criteria with apiVersion/kind, the // TypeMeta should be associated with `ctx` here using: // webhook.GetIncludeTypeMeta(ctx) // // For policies specifying `match:` criteria with label selectors, the // ObjectMeta should be associated with `ctx` here using: // webhook.GetIncludeObjectMeta(ctx) Verify(context.Context, name.Reference, authn.Keychain, ...ociremote.Option) error } // WarningWriter is used to surface warning messages in a manner that // is customizable by callers that's suitable for their execution // environment. The signature is intended to match the standard format string // signature (e.g. Printf, Infof, Logf, Errorf, Fatalf, ...), so functions like // log.Printf or t.Errorf can be passed here directly. type WarningWriter func(string, ...interface{}) // Compile turns a Verification into an executable Verifier. // Any compilation errors are returned here. func Compile(ctx context.Context, v Verification, ww WarningWriter) (Verifier, error) { if err := v.Validate(ctx); err != nil { return nil, err } ipc, err := gather(ctx, v, ww) if err != nil { // This should never hit for validated policies. return nil, err } return &impl{ verification: v, ipc: ipc, ww: ww, }, nil } func gather(ctx context.Context, v Verification, ww WarningWriter) (*config.ImagePolicyConfig, error) { pol := *v.Policies ipc := &config.ImagePolicyConfig{ Policies: make(map[string]webhookcip.ClusterImagePolicy, len(pol)), } for i, p := range pol { content, err := p.fetch(ctx) if err != nil { return nil, err } l, warns, err := ParseClusterImagePolicies(ctx, content) if err != nil { // This path should be unreachable, since we already parse // things during compilation. return nil, fmt.Errorf("parsing policies: %w", err) } if warns != nil { ww("policy %d: %v", i, warns) } // TODO(mattmoor): Add additional checks for unsupported things, // like Match, IncludeSpec, etc. for _, cip := range l { cip.SetDefaults(ctx) if _, ok := ipc.Policies[cip.Name]; ok { ww("duplicate policy named %q, skipping", cip.Name) continue } // We need to roundtrip the policy through JSON here because // the compiled policy expects to be decoded from JSON and only // sets up certain fields when being unmarshalled from JSON, so // things like keyful verification only work when we roundtrip // through JSON. var compiled webhookcip.ClusterImagePolicy if err := convert(webhookcip.ConvertClusterImagePolicyV1alpha1ToWebhook(cip), &compiled); err != nil { ww("roundtripping policy %v", err) continue } ipc.Policies[cip.Name] = compiled } } return ipc, nil } type impl struct { verification Verification ipc *config.ImagePolicyConfig ww WarningWriter } // Check that impl implements Verifier var _ Verifier = (*impl)(nil) // Verify implements Verifier func (i *impl) Verify(ctx context.Context, ref name.Reference, kc authn.Keychain, opts ...ociremote.Option) error { tm := getTypeMeta(ctx) om := getObjectMeta(ctx) matches, err := i.ipc.GetMatchingPolicies(ref.Name(), tm.Kind, tm.APIVersion, om.Labels) if err != nil { return err } if len(matches) == 0 { switch i.verification.NoMatchPolicy { case "allow": return nil case "warn": i.ww("%s is uncovered by policy", ref) case "deny": return fmt.Errorf("%s is uncovered by policy", ref) default: // This is unreachable for a validated Verification. return fmt.Errorf("unsupported noMatchPolicy: %q", i.verification.NoMatchPolicy) } } // Add the keychain to our (optional) list of options. opts = append(opts, ociremote.WithRemoteOptions(remote.WithAuthFromKeychain(kc))) for _, p := range matches { res, errs := webhook.ValidatePolicy(ctx, "" /* namespace */, ref, p, kc, opts...) if res != nil { //nolint: revive // Ignore the errors for other authorities if we got a policy result. } else { // If we didn't get a policy result, then surface any errors. for _, err := range errs { var fe *apis.FieldError if errors.As(err, &fe) { if warnFE := fe.Filter(apis.WarningLevel); warnFE != nil { i.ww("%v", warnFE) } if errorFE := fe.Filter(apis.ErrorLevel); errorFE != nil { return errorFE } } else { return err } } } } return nil } func getTypeMeta(ctx context.Context) (tm metav1.TypeMeta) { raw := webhook.GetIncludeTypeMeta(ctx) if raw == nil { return } _ = convert(raw, &tm) return } func getObjectMeta(ctx context.Context) (om metav1.ObjectMeta) { raw := webhook.GetIncludeObjectMeta(ctx) if raw == nil { return } _ = convert(raw, &om) return } ================================================ FILE: pkg/policy/verifier_test.go ================================================ // Copyright 2023 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. package policy import ( "context" "errors" "fmt" "testing" "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/name" ) const ( // This is the digest of cgr.dev/chainguard/static as of 2023/01/03. // It is verifiable with goodPolicy. staticDigest = "sha256:39ae0654d64cb72003216f6148e581e6d7cf239ac32325867af46666e31739d2" // This is the digest of cgr.dev/chainguard/static as of 2023/01/03. // It is not verifiable with goodPolicy. ancientDigest = "sha256:a9650a15060275287ebf4530b34020b8d998bd2de9aea00d113c332d8c41eb0b" ) func TestVerifierDeny(t *testing.T) { tests := []struct { name string v Verification d name.Digest wantErr error }{{ name: "successful policy evaluation", v: Verification{ NoMatchPolicy: "deny", Policies: &[]Source{{ Data: goodPolicy, }}, }, d: name.MustParseReference("cgr.dev/chainguard/static@" + staticDigest).(name.Digest), }, { name: "no match policy failure", v: Verification{ NoMatchPolicy: "deny", Policies: &[]Source{{ Data: goodPolicy, }}, }, d: name.MustParseReference("cgr.dev/chainguard/busybox@" + staticDigest).(name.Digest), wantErr: errors.New("cgr.dev/chainguard/busybox@sha256:39ae0654d64cb72003216f6148e581e6d7cf239ac32325867af46666e31739d2 is uncovered by policy"), }, { name: "policy evaluation failure", v: Verification{ NoMatchPolicy: "deny", Policies: &[]Source{{ Data: goodPolicy, }}, }, d: name.MustParseReference("cgr.dev/chainguard/static@" + ancientDigest).(name.Digest), wantErr: errors.New("signature keyless validation failed for authority authority-0 for cgr.dev/chainguard/static@sha256:a9650a15060275287ebf4530b34020b8d998bd2de9aea00d113c332d8c41eb0b: no matching signatures: none of the expected identities matched what was in the certificate, got subjects [https://github.com/distroless/static/.github/workflows/release.yaml@refs/heads/main] with issuer https://token.actions.githubusercontent.com: "), }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { vfy, err := Compile(context.Background(), test.v, t.Errorf /* we expect no warnings! */) if err != nil { t.Fatalf("Compile() = %v", err) } gotErr := vfy.Verify(context.Background(), test.d, authn.DefaultKeychain) if (gotErr != nil) != (test.wantErr != nil) { t.Fatalf("Verify() = %v, wanted: %v", gotErr, test.wantErr) } if gotErr != nil && gotErr.Error() != test.wantErr.Error() { t.Fatalf("Verify() = %v, wanted: %v", gotErr, test.wantErr) } }) } } func TestVerifierWarn(t *testing.T) { tests := []struct { name string v Verification d name.Digest wantErr error }{{ name: "successful policy evaluation (warn mode)", v: Verification{ NoMatchPolicy: "warn", Policies: &[]Source{{ Data: goodPolicy, }}, }, d: name.MustParseReference("cgr.dev/chainguard/static@" + staticDigest).(name.Digest), }, { name: "no match policy failure", v: Verification{ NoMatchPolicy: "warn", Policies: &[]Source{{ Data: goodPolicy, }}, }, d: name.MustParseReference("cgr.dev/chainguard/busybox@" + staticDigest).(name.Digest), wantErr: errors.New("cgr.dev/chainguard/busybox@sha256:39ae0654d64cb72003216f6148e581e6d7cf239ac32325867af46666e31739d2 is uncovered by policy"), }, { name: "policy evaluation failure (warn mode)", v: Verification{ NoMatchPolicy: "deny", Policies: &[]Source{{ Data: goodPolicy + " mode: warn", }}, }, d: name.MustParseReference("cgr.dev/chainguard/static@" + ancientDigest).(name.Digest), wantErr: errors.New("signature keyless validation failed for authority authority-0 for cgr.dev/chainguard/static@sha256:a9650a15060275287ebf4530b34020b8d998bd2de9aea00d113c332d8c41eb0b: no matching signatures: none of the expected identities matched what was in the certificate, got subjects [https://github.com/distroless/static/.github/workflows/release.yaml@refs/heads/main] with issuer https://token.actions.githubusercontent.com: "), }, { name: "duplicate policies", v: Verification{ NoMatchPolicy: "deny", // This is always surfaced as a warning. Policies: &[]Source{{ Data: goodPolicy, }, { Data: goodPolicy, }}, }, d: name.MustParseReference("cgr.dev/chainguard/static@" + staticDigest).(name.Digest), wantErr: errors.New(`duplicate policy named "ko-default-base-image-policy", skipping`), }} for _, test := range tests { t.Run("warn: "+test.name, func(t *testing.T) { var gotErr error vfy, err := Compile(context.Background(), test.v, func(s string, i ...interface{}) { gotErr = fmt.Errorf(s, i...) }) if err != nil { t.Fatalf("Compile() = %v", err) } err = vfy.Verify(context.Background(), test.d, authn.DefaultKeychain) if err != nil { t.Fatalf("Verify() = %v", err) } if (gotErr != nil) != (test.wantErr != nil) { t.Fatalf("Verify() = %v, wanted: %v", gotErr, test.wantErr) } if gotErr != nil && gotErr.Error() != test.wantErr.Error() { t.Fatalf("Verify() = %v, wanted: %v", gotErr, test.wantErr) } }) } } ================================================ FILE: pkg/reconciler/clusterimagepolicy/clusterimagepolicy.go ================================================ // 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. package clusterimagepolicy import ( "context" "crypto" "crypto/sha256" "fmt" "io" "net/http" "strings" "github.com/sigstore/policy-controller/pkg/apis/config" "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" "github.com/sigstore/policy-controller/pkg/apis/signaturealgo" clusterimagepolicyreconciler "github.com/sigstore/policy-controller/pkg/client/injection/reconciler/policy/v1alpha1/clusterimagepolicy" "github.com/sigstore/policy-controller/pkg/reconciler/clusterimagepolicy/resources" webhookcip "github.com/sigstore/policy-controller/pkg/webhook/clusterimagepolicy" "github.com/sigstore/sigstore/pkg/cryptoutils" corev1 "k8s.io/api/core/v1" apierrs "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" corev1listers "k8s.io/client-go/listers/core/v1" "knative.dev/pkg/logging" "knative.dev/pkg/reconciler" "knative.dev/pkg/system" "knative.dev/pkg/tracker" sigs "github.com/sigstore/cosign/v3/pkg/signature" "github.com/sigstore/sigstore/pkg/signature/kms" signatureoptions "github.com/sigstore/sigstore/pkg/signature/options" ) // Reconciler implements clusterimagepolicyreconciler.Interface for // ClusterImagePolicy resources. type Reconciler struct { // Tracker builds an index of what resources are watching other resources // so that we can immediately react to changes tracked resources. tracker tracker.Interface // We need to be able to read Secrets, which are really holding public // keys. secretlister corev1listers.SecretLister configmaplister corev1listers.ConfigMapLister kubeclient kubernetes.Interface } // Check that our Reconciler implements Interface as well as finalizer var _ clusterimagepolicyreconciler.Interface = (*Reconciler)(nil) var _ clusterimagepolicyreconciler.Finalizer = (*Reconciler)(nil) // ReconcileKind implements Interface.ReconcileKind. func (r *Reconciler) ReconcileKind(ctx context.Context, cip *v1alpha1.ClusterImagePolicy) reconciler.Event { cip.Status.InitializeConditions() cipCopy, cipErr := r.inlinePublicKeys(ctx, cip) if cipErr != nil { r.handleCIPError(ctx, cip.Name) // Update the status to reflect that we were unable to inline keys. cip.Status.MarkInlineKeysFailed(cipErr.Error()) // Note that we return the error about the Invalid cip here to make // sure that it's surfaced. return cipErr } cip.Status.MarkInlineKeysOk() cipErr = r.inlinePolicies(ctx, cipCopy) if cipErr != nil { r.handleCIPError(ctx, cip.Name) // Update the status to reflect that we were unable to inline policies. cip.Status.MarkInlinePoliciesFailed(cipErr.Error()) // Note that we return the error about the Invalid cip here to make // sure that it's surfaced. return cipErr } cip.Status.MarkInlinePoliciesOk() webhookCIP := webhookcip.ConvertClusterImagePolicyV1alpha1ToWebhook(cipCopy) // See if the CM holding configs exists existing, err := r.configmaplister.ConfigMaps(system.Namespace()).Get(config.ImagePoliciesConfigName) if err != nil { if !apierrs.IsNotFound(err) { logging.FromContext(ctx).Errorf("Failed to get configmap: %v", err) cip.Status.MarkCMUpdateFailed(err.Error()) return err } // Does not exist, create it. cm, err := resources.NewConfigMap(system.Namespace(), config.ImagePoliciesConfigName, cip.Name, webhookCIP) if err != nil { logging.FromContext(ctx).Errorf("Failed to construct configmap: %v", err) cip.Status.MarkCMUpdateFailed(err.Error()) return err } _, err = r.kubeclient.CoreV1().ConfigMaps(system.Namespace()).Create(ctx, cm, metav1.CreateOptions{}) if err != nil { cip.Status.MarkCMUpdateFailed(err.Error()) return err } cip.Status.MarkCMUpdatedOK() return err } // Check if we need to update the configmap or not. patchBytes, err := resources.CreatePatch(system.Namespace(), config.ImagePoliciesConfigName, cip.Name, existing.DeepCopy(), webhookCIP) if err != nil { logging.FromContext(ctx).Errorf("Failed to create patch: %v", err) cip.Status.MarkCMUpdateFailed(err.Error()) return err } if len(patchBytes) > 0 { _, err = r.kubeclient.CoreV1().ConfigMaps(system.Namespace()).Patch(ctx, config.ImagePoliciesConfigName, types.JSONPatchType, patchBytes, metav1.PatchOptions{}) if err != nil { cip.Status.MarkCMUpdateFailed(err.Error()) return err } } cip.Status.MarkCMUpdatedOK() return nil } // FinalizeKind implements Interface.ReconcileKind. func (r *Reconciler) FinalizeKind(ctx context.Context, cip *v1alpha1.ClusterImagePolicy) reconciler.Event { // See if the CM holding configs even exists existing, err := r.configmaplister.ConfigMaps(system.Namespace()).Get(config.ImagePoliciesConfigName) if err != nil { if !apierrs.IsNotFound(err) { // There's very little we can do here. This could happen if it's // intermittent error, which is fine when we retry. But if something // goofy happens like we lost access to it, then it's a bit of a // pickle since the entry will exist there and we can't remove it. // So keep trying. Other option would be just to bail. logging.FromContext(ctx).Errorf("Failed to get configmap: %v", err) return err } // Since the CM doesn't exist, there's nothing for us to clean up. return nil } // CM exists, so remove our entry from it. return r.removeCIPEntry(ctx, existing, cip.Name) } func (r *Reconciler) handleCIPError(ctx context.Context, cipName string) { // The CIP is invalid, try to remove CIP from the configmap existing, err := r.configmaplister.ConfigMaps(system.Namespace()).Get(config.ImagePoliciesConfigName) if err != nil { if !apierrs.IsNotFound(err) { logging.FromContext(ctx).Errorf("Failed to get configmap: %v", err) } } else if err := r.removeCIPEntry(ctx, existing, cipName); err != nil { logging.FromContext(ctx).Errorf("Failed to remove CIP entry from configmap: %v", err) } } // inlinePublicKeys will go through the CIP and try to read the referenced // secrets, KMS keys and convert them into inlined data. Makes a copy of the CIP // before modifying it and returns the copy. func (r *Reconciler) inlinePublicKeys(ctx context.Context, cip *v1alpha1.ClusterImagePolicy) (*v1alpha1.ClusterImagePolicy, error) { ret := cip.DeepCopy() for _, authority := range ret.Spec.Authorities { if authority.Key != nil && authority.Key.SecretRef != nil { if err := r.inlineAndTrackSecret(ctx, ret, authority.Key); err != nil { logging.FromContext(ctx).Errorf("Failed to read secret %q: %v", authority.Key.SecretRef.Name, err) return nil, err } } if authority.Keyless != nil && authority.Keyless.CACert != nil && authority.Keyless.CACert.SecretRef != nil { if err := r.inlineAndTrackSecret(ctx, ret, authority.Keyless.CACert); err != nil { logging.FromContext(ctx).Errorf("Failed to read secret %q: %v", authority.Keyless.CACert.SecretRef.Name, err) return nil, err } } if authority.Key != nil && strings.Contains(authority.Key.KMS, "://") { pubKeyString, err := getKMSPublicKey(ctx, authority.Key.KMS, authority.Key.HashAlgorithm) if err != nil { return nil, err } authority.Key.Data = pubKeyString authority.Key.KMS = "" } } return ret, nil } // getKMSPublicKey returns the public key as a string from the configured KMS service using the key ID func getKMSPublicKey(ctx context.Context, keyID string, hashAlgorithm string) (string, error) { algorithm := crypto.SHA256 if hashAlgorithm != "" { var err error algorithm, err = signaturealgo.HashAlgorithm(hashAlgorithm) if err != nil { logging.FromContext(ctx).Errorf("Failed to extract the signature hash algorithm: %w", err) return "", fmt.Errorf("failed to extract the signature hash algorithm: %w", err) } } kmsSigner, err := kms.Get(ctx, keyID, algorithm) if err != nil { logging.FromContext(ctx).Errorf("Failed to read KMS key ID %q: %v", keyID, err) return "", err } pemBytes, err := sigs.PublicKeyPem(kmsSigner, signatureoptions.WithContext(ctx)) if err != nil { return "", err } return string(pemBytes), nil } // inlineSecret will take in a KeyRef and tries to read the Secret, finding the // first key from it and will inline it in place of Data and then clear out // the SecretRef and return it. // Additionally, we set up a tracker so we will be notified if the secret // is modified. // There's still some discussion about how to handle multiple keys in a secret // for now, just grab one from it. For reference, the discussion is here: // TODO(vaikas): https://github.com/sigstore/cosign/issues/1573 func (r *Reconciler) inlineAndTrackSecret(ctx context.Context, cip *v1alpha1.ClusterImagePolicy, keyref *v1alpha1.KeyRef) error { if err := r.tracker.TrackReference(tracker.Reference{ APIVersion: "v1", Kind: "Secret", Namespace: system.Namespace(), Name: keyref.SecretRef.Name, }, cip); err != nil { return fmt.Errorf("failed to track changes to secret %q : %w", keyref.SecretRef.Name, err) } secret, err := r.secretlister.Secrets(system.Namespace()).Get(keyref.SecretRef.Name) if err != nil { return err } if len(secret.Data) == 0 { return fmt.Errorf("secret %q contains no data", keyref.SecretRef.Name) } if len(secret.Data) > 1 { return fmt.Errorf("secret %q contains multiple data entries, only one is supported", keyref.SecretRef.Name) } for k, v := range secret.Data { logging.FromContext(ctx).Infof("inlining secret %q key %q", keyref.SecretRef.Name, k) publicKey, err := cryptoutils.UnmarshalPEMToPublicKey(v) if err != nil || publicKey == nil { return fmt.Errorf("secret %q contains an invalid public key: %w", keyref.SecretRef.Name, err) } keyref.Data = string(v) keyref.SecretRef = nil } return nil } // inlinePolicies will go through the CIP and try to read the referenced // ConfigMapRefs and convert them into inlined data. Modifies the cip in-place func (r *Reconciler) inlinePolicies(ctx context.Context, cip *v1alpha1.ClusterImagePolicy) error { for _, authority := range cip.Spec.Authorities { for _, att := range authority.Attestations { if att.Policy != nil && att.Policy.ConfigMapRef != nil { err := r.inlineAndTrackConfigMap(ctx, cip, att.Policy) if err != nil { logging.FromContext(ctx).Errorf("Failed to read configmap %q: %v", att.Policy.ConfigMapRef.Name, err) return err } } if att.Policy != nil && att.Policy.Remote != nil { err := r.inlinePolicyURL(ctx, att.Policy) if err != nil { logging.FromContext(ctx).Errorf("Failed to read policy url %s: %v", cip.Spec.Policy.Remote.URL.String(), err) return err } } } } if cip.Spec.Policy != nil && cip.Spec.Policy.ConfigMapRef != nil { err := r.inlineAndTrackConfigMap(ctx, cip, cip.Spec.Policy) if err != nil { logging.FromContext(ctx).Errorf("Failed to read configmap %q: %v", cip.Spec.Policy.ConfigMapRef.Name, err) return err } } if cip.Spec.Policy != nil && cip.Spec.Policy.Remote != nil { err := r.inlinePolicyURL(ctx, cip.Spec.Policy) if err != nil { logging.FromContext(ctx).Errorf("Failed to read policy url %s: %v", cip.Spec.Policy.Remote.URL.String(), err) return err } } return nil } func (r *Reconciler) inlinePolicyURL(ctx context.Context, policyRef *v1alpha1.Policy) error { logging.FromContext(ctx).Infof("inlining policy url %q", policyRef.Remote.URL.String()) resp, err := http.Get(policyRef.Remote.URL.String()) if err != nil { return fmt.Errorf("failed to fetch content from policy url: %w", err) } defer resp.Body.Close() if resp.StatusCode < 200 || resp.StatusCode > 299 { return fmt.Errorf("failed to fetch content from policy url with code %q", resp.StatusCode) } data, err := io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("failed to read policy url response: %w", err) } // Checking the sha256sum value in comparison with the one set in the policy sha256Sum := fmt.Sprintf("%x", sha256.Sum256(data)) if sha256Sum != policyRef.Remote.Sha256sum { return fmt.Errorf("failed to check sha256sum from policy remote: %s got %s", policyRef.Remote.Sha256sum, sha256Sum) } policyRef.Data = string(data) policyRef.Remote = nil return nil } // inlineAndTrackConfigMap will take in a ConfigMapRef and tries to read the ConfigMap, // finding the first key from it and will inline it in place of Data and then // clear out the ConfigMapRef and return it. // Additionally, we set up a tracker so we will be notified if the ConfigMap // is modified. func (r *Reconciler) inlineAndTrackConfigMap(ctx context.Context, cip *v1alpha1.ClusterImagePolicy, policyRef *v1alpha1.Policy) error { cmName := policyRef.ConfigMapRef.Name keyName := policyRef.ConfigMapRef.Key if err := r.tracker.TrackReference(tracker.Reference{ APIVersion: "v1", Kind: "ConfigMap", Namespace: system.Namespace(), Name: cmName, }, cip); err != nil { return fmt.Errorf("failed to track changes to configmap %q : %w", cmName, err) } cm, err := r.configmaplister.ConfigMaps(system.Namespace()).Get(cmName) if err != nil { return err } if len(cm.Data) == 0 { return fmt.Errorf("configmap %q contains no data", cmName) } if cm.Data[keyName] == "" { return fmt.Errorf("configmap %q does not contain key %s", cmName, keyName) } logging.FromContext(ctx).Infof("inlining configmap %q key %q", cmName, keyName) policyRef.Data = cm.Data[keyName] policyRef.ConfigMapRef = nil return nil } // removeCIPEntry removes an entry from a CM. If no entry exists, it's a nop. func (r *Reconciler) removeCIPEntry(ctx context.Context, cm *corev1.ConfigMap, cipName string) error { patchBytes, err := resources.CreateRemovePatch(system.Namespace(), config.ImagePoliciesConfigName, cm.DeepCopy(), cipName) if err != nil { logging.FromContext(ctx).Errorf("Failed to create remove patch: %v", err) return err } if len(patchBytes) > 0 { _, err = r.kubeclient.CoreV1().ConfigMaps(system.Namespace()).Patch(ctx, config.ImagePoliciesConfigName, types.JSONPatchType, patchBytes, metav1.PatchOptions{}) return err } return nil } ================================================ FILE: pkg/reconciler/clusterimagepolicy/clusterimagepolicy_test.go ================================================ // 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. package clusterimagepolicy import ( "context" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "fmt" "net/http" "net/http/httptest" "strings" "testing" logtesting "knative.dev/pkg/logging/testing" "github.com/sigstore/policy-controller/pkg/apis/config" "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" "github.com/sigstore/policy-controller/pkg/apis/signaturealgo" fakecosignclient "github.com/sigstore/policy-controller/pkg/client/injection/client/fake" "github.com/sigstore/policy-controller/pkg/client/injection/reconciler/policy/v1alpha1/clusterimagepolicy" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" clientgotesting "k8s.io/client-go/testing" "knative.dev/pkg/apis" fakekubeclient "knative.dev/pkg/client/injection/kube/client/fake" "knative.dev/pkg/configmap" "knative.dev/pkg/controller" "knative.dev/pkg/system" "knative.dev/pkg/tracker" . "github.com/sigstore/policy-controller/pkg/reconciler/testing/v1alpha1" . "knative.dev/pkg/reconciler/testing" _ "knative.dev/pkg/system/testing" "github.com/sigstore/sigstore/pkg/signature/kms/fake" ) const ( cipName = "test-cip" cipKMSName = "test-kms-cip" testKey = "test-cip" cipName2 = "test-cip-2" testKey2 = "test-cip-2" keySecretName = "publickey-key" keylessSecretName = "publickey-keyless" glob = "ghcr.io/example/*" fakeKMSKey = "fakekms://keycip" policyCMName = "policy-configmap" policyCMKey = "policy-configmap-key" testPolicy = `predicateType: "cosign.sigstore.dev/attestation/v1" predicate: Data: "foobar key e2e test"` // This is above ran through shasum -a 256. Note that there's no trailing // newline. testPolicySHA256 = "c694cc08146070e84751ce7416d4befd70ea779071f457df8127586a29ac6580" // Same as above with one change just to make it fail testPolicySHA256Bad = "c694cc08146070e84751ce7416d4befd70ea779071f457df8107586a29ac6580" // Just some public key that was laying around, only format matters. validPublicKeyData = `-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J RCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ== -----END PUBLIC KEY-----` // This is the patch for replacing a single entry in the ConfigMap replaceCIPPatch = `[{"op":"replace","path":"/data/test-cip","value":"{\"uid\":\"test-uid\",\"resourceVersion\":\"0123456789\",\"images\":[{\"glob\":\"ghcr.io/example/*\"}],\"authorities\":[{\"name\":\"authority-0\",\"key\":{\"data\":\"-----BEGIN PUBLIC KEY-----\\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J\\nRCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ==\\n-----END PUBLIC KEY-----\",\"hashAlgorithm\":\"sha256\"}}],\"mode\":\"enforce\"}"}]` // This is the patch for adding an entry for non-existing KMS for cipName2 addCIP2Patch = `[{"op":"add","path":"/data/test-cip-2","value":"{\"uid\":\"test-uid\",\"resourceVersion\":\"0123456789\",\"images\":[{\"glob\":\"ghcr.io/example/*\"}],\"authorities\":[{\"name\":\"authority-0\",\"key\":{\"data\":\"-----BEGIN PUBLIC KEY-----\\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J\\nRCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ==\\n-----END PUBLIC KEY-----\",\"hashAlgorithm\":\"sha256\"}}],\"mode\":\"enforce\"}"}]` // This is the patch for removing the last entry, leaving just the // configmap objectmeta, no data. removeDataPatch = `[{"op":"remove","path":"/data"}]` // This is the patch for removing only a single entry from a map that has // two entries but only one is being removed. For key entry removeSingleEntryKeyPatch = `[{"op":"remove","path":"/data/test-cip"}]` // This is the patch for removing only a single entry from a map that has // two entries but only one is being removed. For keyless entry. removeSingleEntryKeylessPatch = `[{"op":"remove","path":"/data/test-cip-2"}]` // This is the patch for inlined cip policy configmap ref. inlinedPolicyPatch = `[{"op":"replace","path":"/data/test-cip","value":"{\"uid\":\"test-uid\",\"resourceVersion\":\"0123456789\",\"images\":[{\"glob\":\"ghcr.io/example/*\"}],\"authorities\":[{\"name\":\"authority-0\",\"static\":{\"action\":\"pass\"}}],\"policy\":{\"name\":\"\",\"predicateType\":\"\",\"type\":\"cue\",\"data\":\"predicateType: \\\"cosign.sigstore.dev/attestation/v1\\\"\\npredicate: Data: \\\"foobar key e2e test\\\"\"},\"mode\":\"enforce\"}"}]` // This is the patch for inlined secret for keyless cakey ref data inlinedSecretKeylessPatch = `[{"op":"replace","path":"/data/test-cip-2","value":"{\"uid\":\"test-uid\",\"resourceVersion\":\"0123456789\",\"images\":[{\"glob\":\"ghcr.io/example/*\"}],\"authorities\":[{\"name\":\"authority-0\",\"keyless\":{\"identities\":[{\"issuerRegExp\":\"iss.*\",\"subjectRegExp\":\"sub.*\"}],\"ca-cert\":{\"data\":\"-----BEGIN PUBLIC KEY-----\\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J\\nRCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ==\\n-----END PUBLIC KEY-----\",\"hashAlgorithm\":\"sha256\"}}}],\"mode\":\"enforce\"}"}]` // This is the patch for inlined secret with matching resource, version and group inlinedSecretKeylessMatchResourcePatch = `[{"op":"replace","path":"/data/test-cip-2","value":"{\"uid\":\"test-uid\",\"resourceVersion\":\"0123456789\",\"images\":[{\"glob\":\"ghcr.io/example/*\"}],\"authorities\":[{\"name\":\"authority-0\",\"keyless\":{\"identities\":[{\"issuerRegExp\":\"iss.*\",\"subjectRegExp\":\"sub.*\"}],\"ca-cert\":{\"data\":\"-----BEGIN PUBLIC KEY-----\\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J\\nRCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ==\\n-----END PUBLIC KEY-----\",\"hashAlgorithm\":\"sha256\"}}}],\"mode\":\"enforce\",\"match\":[{\"group\":\"apps\",\"version\":\"v1\",\"resource\":\"deployments\"}]}"}]` // This is the patch for inlined secret with matching labels inlinedSecretKeylessMatchLabelsPatch = `[{"op":"replace","path":"/data/test-cip-2","value":"{\"uid\":\"test-uid\",\"resourceVersion\":\"0123456789\",\"images\":[{\"glob\":\"ghcr.io/example/*\"}],\"authorities\":[{\"name\":\"authority-0\",\"keyless\":{\"identities\":[{\"issuerRegExp\":\"iss.*\",\"subjectRegExp\":\"sub.*\"}],\"ca-cert\":{\"data\":\"-----BEGIN PUBLIC KEY-----\\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J\\nRCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ==\\n-----END PUBLIC KEY-----\",\"hashAlgorithm\":\"sha256\"}}}],\"mode\":\"enforce\",\"match\":[{\"group\":\"apps\",\"version\":\"v1\",\"resource\":\"replicasets\",\"selector\":{\"matchLabels\":{\"match\":\"match\"}}}]}"}]` replaceCIPKeySourcePatch = `[{"op":"replace","path":"/data/test-cip","value":"{\"uid\":\"test-uid\",\"resourceVersion\":\"0123456789\",\"images\":[{\"glob\":\"ghcr.io/example/*\"}],\"authorities\":[{\"name\":\"authority-0\",\"key\":{\"data\":\"-----BEGIN PUBLIC KEY-----\\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J\\nRCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ==\\n-----END PUBLIC KEY-----\",\"hashAlgorithm\":\"sha256\"},\"source\":[{\"oci\":\"example.com/alternative/signature\",\"signaturePullSecrets\":[{\"name\":\"signaturePullSecretName\"}]}]}],\"mode\":\"enforce\"}"}]` replaceCIPKeySourceWithoutOCIPatch = `[{"op":"replace","path":"/data/test-cip","value":"{\"uid\":\"test-uid\",\"resourceVersion\":\"0123456789\",\"images\":[{\"glob\":\"ghcr.io/example/*\"}],\"authorities\":[{\"name\":\"authority-0\",\"key\":{\"data\":\"-----BEGIN PUBLIC KEY-----\\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J\\nRCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ==\\n-----END PUBLIC KEY-----\",\"hashAlgorithm\":\"sha256\"},\"source\":[{\"signaturePullSecrets\":[{\"name\":\"signaturePullSecretName\"}]}]}],\"mode\":\"enforce\"}"}]` resourceVersion = "0123456789" uid = "test-uid" statusUpdateFailureFmt = `Failed to update status for "test-cip": invalid value: %s: spec.remote.url url valid is invalid. host and https scheme are expected` invalidSHAMsg = "failed to check sha256sum from policy remote: c694cc08146070e84751ce7416d4befd70ea779071f457df8107586a29ac6580 got c694cc08146070e84751ce7416d4befd70ea779071f457df8127586a29ac6580" ) var ( // Just define these here so that we can use them in various identity // places where we just need a placeholder. placeholderIdentities = []v1alpha1.Identity{{SubjectRegExp: "sub.*", IssuerRegExp: "iss.*"}} ) func TestReconcile(t *testing.T) { privKMSKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatalf("error generating ecdsa private key: %v", err) } mainContext := context.WithValue(context.Background(), fake.KmsCtxKey{}, privKMSKey) // Note that this is just an HTTP server, so it will cause a problem // after the Status update because of the upstream does not appear to set // the apis.IsInStatusUpdate correctly in the tests. So it validates the // status update even though it shouldn't. This is tested elsewhere, so // we just work around it here by expecting that benign error. policyServerGood := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { rw.Write([]byte(testPolicy)) })) t.Cleanup(policyServerGood.Close) policyURLGood, err := apis.ParseURL(policyServerGood.URL) if err != nil { t.Fatalf("Failed to parse the URL: %v", err) } statusUpdateFailureMsg := fmt.Sprintf(statusUpdateFailureFmt, policyURLGood.String()) table := TableTest{{ Name: "bad workqueue key", // Make sure Reconcile handles bad keys. Key: "too/many/parts", }, { Name: "key not found", // Make sure Reconcile handles good keys that don't exist. Key: "foo/not-found", }, { Name: "ClusterImagePolicy not found", Key: testKey, }, { Name: "ClusterImagePolicy is being deleted, doesn't exist, no changes", Key: testKey, Objects: []runtime.Object{ NewClusterImagePolicy(cipName, WithClusterImagePolicyDeletionTimestamp), }, }, { Name: "ClusterImagePolicy with glob and inline key data, added to cm and finalizer", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithMode("warn"), WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ Data: validPublicKeyData, }}))}, WantCreates: []runtime.Object{ makeConfigMapWithWarn(), }, WantPatches: []clientgotesting.PatchActionImpl{ patchFinalizers(system.Namespace(), cipName), }, WantEvents: []string{ Eventf(corev1.EventTypeNormal, "FinalizerUpdate", `Updated "test-cip" finalizers`), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithMode("warn"), WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ Data: validPublicKeyData, }}), MarkReady), }}, }, { Name: "ClusterImagePolicy with glob and inline key data, already exists, no patch, no status update", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithMode("enforce"), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ Data: validPublicKeyData, }}), MarkReady), makeConfigMap(), }, }, { Name: "ClusterImagePolicy with glob and inline key data, needs a patch", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ Data: validPublicKeyData, }})), makeDifferentConfigMap(), }, WantPatches: []clientgotesting.PatchActionImpl{ makePatch(replaceCIPPatch), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ Data: validPublicKeyData, }}), MarkReady), }}, }, { Name: "ClusterImagePolicy with glob and inline key data, needs a patch but fails", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ Data: validPublicKeyData, }})), makeDifferentConfigMap(), }, WantPatches: []clientgotesting.PatchActionImpl{ makePatch(replaceCIPPatch), }, WithReactors: []clientgotesting.ReactionFunc{ InduceFailure("patch", "configmaps"), }, WantErr: true, WantEvents: []string{ Eventf(corev1.EventTypeWarning, "InternalError", "inducing failure for patch configmaps"), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ Data: validPublicKeyData, }}), WithInitConditions, WithObservedGeneration(1), WithMarkInlineKeysOk, WithMarkInlinePoliciesOk, WithMarkCMUpdateFailed("inducing failure for patch configmaps"), ), }}, }, { Name: "ClusterImagePolicy with glob and KMS key data, added as a patch", Key: testKey2, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName2, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ Data: validPublicKeyData, }})), makeConfigMap(), // Make the existing configmap }, WantPatches: []clientgotesting.PatchActionImpl{ makePatch(addCIP2Patch), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipName2, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ Data: validPublicKeyData, }}), MarkReady), }}, }, { Name: "ClusterImagePolicy with glob and inline key data, already exists, deleted", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ Data: validPublicKeyData, }}), WithClusterImagePolicyDeletionTimestamp), makeConfigMap(), }, WantPatches: []clientgotesting.PatchActionImpl{ patchRemoveFinalizers(system.Namespace(), cipName), makePatch(removeDataPatch), }, WantEvents: []string{ Eventf(corev1.EventTypeNormal, "FinalizerUpdate", `Updated "test-cip" finalizers`), }, }, { Name: "Two entries, remove only one", Key: testKey2, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName2, WithFinalizer, WithUID(uid), WithResourceVersion(resourceVersion), WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ Data: validPublicKeyData, }}), WithClusterImagePolicyDeletionTimestamp), makeConfigMapWithTwoEntries(), }, WantPatches: []clientgotesting.PatchActionImpl{ patchRemoveFinalizers(system.Namespace(), cipName2), makePatch(removeSingleEntryKeylessPatch), }, WantEvents: []string{ Eventf(corev1.EventTypeNormal, "FinalizerUpdate", `Updated "test-cip-2" finalizers`), }, }, { Name: "Key with secret, secret does not exist, no entry in configmap", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keySecretName, }, }}), ), makeEmptyConfigMap(), }, WantErr: true, WantEvents: []string{ Eventf(corev1.EventTypeWarning, "InternalError", `secret "publickey-key" not found`), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keySecretName, }, }}), WithInitConditions, WithObservedGeneration(1), WithMarkInlineKeysFailed(`secret "publickey-key" not found`)), }}, PostConditions: []func(*testing.T, *TableRow){ AssertTrackingSecret(system.Namespace(), keySecretName), }, }, { Name: "Key with secret, secret does not exist, entry removed from configmap", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keySecretName, }, }}), ), makeConfigMapWithTwoEntries(), }, WantErr: true, WantEvents: []string{ Eventf(corev1.EventTypeWarning, "InternalError", `secret "publickey-key" not found`), }, WantPatches: []clientgotesting.PatchActionImpl{ makePatch(removeSingleEntryKeyPatch), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keySecretName, }, }}), WithInitConditions, WithObservedGeneration(1), WithMarkInlineKeysFailed(`secret "publickey-key" not found`)), }}, PostConditions: []func(*testing.T, *TableRow){ AssertTrackingSecret(system.Namespace(), keySecretName), }, }, { Name: "Key with secret, secret does not exist, cm does not exist", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keySecretName, }, }}), ), }, WantErr: true, WantEvents: []string{ Eventf(corev1.EventTypeWarning, "InternalError", `secret "publickey-key" not found`), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keySecretName, }, }}), WithInitConditions, WithObservedGeneration(1), WithMarkInlineKeysFailed(`secret "publickey-key" not found`)), }}, PostConditions: []func(*testing.T, *TableRow){ AssertTrackingSecret(system.Namespace(), keySecretName), }, }, { Name: "Keyless with secret, secret does not exist.", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Keyless: &v1alpha1.KeylessRef{ CACert: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keylessSecretName, }, }, Identities: placeholderIdentities, }}), ), makeConfigMapWithTwoEntries(), }, WantErr: true, WantEvents: []string{ Eventf(corev1.EventTypeWarning, "InternalError", `secret "publickey-keyless" not found`), }, WantPatches: []clientgotesting.PatchActionImpl{ makePatch(removeSingleEntryKeyPatch), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Keyless: &v1alpha1.KeylessRef{ CACert: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keylessSecretName, }, }, Identities: placeholderIdentities, }}), WithInitConditions, WithObservedGeneration(1), WithMarkInlineKeysFailed(`secret "publickey-keyless" not found`)), }}, PostConditions: []func(*testing.T, *TableRow){ AssertTrackingSecret(system.Namespace(), keylessSecretName), }, }, { Name: "Key with secret, no data.", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keySecretName, }, }}), ), &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Namespace: system.Namespace(), Name: keySecretName, }, }, makeEmptyConfigMap(), }, WantErr: true, WantEvents: []string{ Eventf(corev1.EventTypeWarning, "InternalError", `secret "publickey-key" contains no data`), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keySecretName, }, }}), WithInitConditions, WithObservedGeneration(1), WithMarkInlineKeysFailed(`secret "publickey-key" contains no data`)), }}, PostConditions: []func(*testing.T, *TableRow){ AssertTrackingSecret(system.Namespace(), keySecretName), }, }, { Name: "Key with secret, multiple data entries.", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keySecretName, }, }}), ), &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Namespace: system.Namespace(), Name: keySecretName, }, Data: map[string][]byte{ "first": []byte("first data"), "second": []byte("second data"), }, }, makeEmptyConfigMap(), }, WantErr: true, WantEvents: []string{ Eventf(corev1.EventTypeWarning, "InternalError", `secret "publickey-key" contains multiple data entries, only one is supported`), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keySecretName, }, }}), WithInitConditions, WithObservedGeneration(1), WithMarkInlineKeysFailed(`secret "publickey-key" contains multiple data entries, only one is supported`)), }}, PostConditions: []func(*testing.T, *TableRow){ AssertTrackingSecret(system.Namespace(), keySecretName), }, }, { Name: "Key with secret, secret exists, invalid public key", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keySecretName, }, }}), ), makeEmptyConfigMap(), makeSecret(keySecretName, "garbage secret value, not a public key"), }, WantErr: true, WantEvents: []string{ Eventf(corev1.EventTypeWarning, "InternalError", `secret "publickey-key" contains an invalid public key: PEM decoding failed`), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keySecretName, }, }}), WithInitConditions, WithObservedGeneration(1), WithMarkInlineKeysFailed(`secret "publickey-key" contains an invalid public key: PEM decoding failed`)), }}, PostConditions: []func(*testing.T, *TableRow){ AssertTrackingSecret(system.Namespace(), keySecretName), }, }, { Name: "Key with secret, secret exists, inlined", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keySecretName, }, }}), ), makeSecret(keySecretName, validPublicKeyData), }, WantCreates: []runtime.Object{ makeConfigMap(), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keySecretName, }, }}), MarkReady), }}, PostConditions: []func(*testing.T, *TableRow){ AssertTrackingSecret(system.Namespace(), keySecretName), }, }, { Name: "Keyless with secret, secret exists, inlined", Key: testKey2, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName2, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Keyless: &v1alpha1.KeylessRef{ CACert: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keylessSecretName, }}, Identities: placeholderIdentities, }}), ), makeConfigMapWithTwoEntries(), makeSecret(keylessSecretName, validPublicKeyData), }, WantPatches: []clientgotesting.PatchActionImpl{ makePatch(inlinedSecretKeylessPatch), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipName2, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Keyless: &v1alpha1.KeylessRef{ CACert: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keylessSecretName, }}, Identities: placeholderIdentities, }}), MarkReady), }}, PostConditions: []func(*testing.T, *TableRow){ AssertTrackingSecret(system.Namespace(), keylessSecretName), }, }, { Name: "ClusterImagePolicy with glob and KMS key, added the data after querying the fake signer", Key: cipKMSName, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipKMSName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ KMS: fakeKMSKey, HashAlgorithm: signaturealgo.DefaultSignatureAlgorithm, }})), makeEmptyConfigMap(), // Make the existing configmap }, WantPatches: []clientgotesting.PatchActionImpl{ patchKMS(mainContext, t, fakeKMSKey, signaturealgo.DefaultSignatureAlgorithm), }, // TODO(vaikas): We have to do some upstream work here. Doing // status updates does not behave correctly by setting the // IsInStatusUpdate in Table Driven tests. // This means, that even though we're sending a valid request to // only patch the status subResource, the validate logic is still // ran and results in an error that's not an error in real // reconciler. WantEvents: []string{ Eventf(corev1.EventTypeWarning, "UpdateFailed", `Failed to update status for "test-kms-cip": invalid value: fakekms://keycip: spec.authorities[0].key.kms malformed KMS format, should be prefixed by any of the supported providers: [awskms:// azurekms:// hashivault:// gcpkms://]`), }, WantErr: true, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipKMSName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ KMS: fakeKMSKey, HashAlgorithm: signaturealgo.DefaultSignatureAlgorithm, }}), MarkReady), }}, }, { Name: "Key with data, source, and signature pull secrets", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ Data: validPublicKeyData, }, Sources: []v1alpha1.Source{{ OCI: "example.com/alternative/signature", SignaturePullSecrets: []corev1.LocalObjectReference{ {Name: "signaturePullSecretName"}, }, }}, }), ), makeConfigMap(), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ Data: validPublicKeyData, }, Sources: []v1alpha1.Source{{ OCI: "example.com/alternative/signature", SignaturePullSecrets: []corev1.LocalObjectReference{ {Name: "signaturePullSecretName"}, }, }}}), MarkReady), }}, WantPatches: []clientgotesting.PatchActionImpl{ makePatch(replaceCIPKeySourcePatch), }, }, { Name: "Key with data, source, no oci but signature pull secrets", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ Data: validPublicKeyData, }, Sources: []v1alpha1.Source{{ SignaturePullSecrets: []corev1.LocalObjectReference{ {Name: "signaturePullSecretName"}, }, }}, }), ), makeConfigMap(), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ Data: validPublicKeyData, }, Sources: []v1alpha1.Source{{ SignaturePullSecrets: []corev1.LocalObjectReference{ {Name: "signaturePullSecretName"}, }, }}, }), MarkReady), }}, WantPatches: []clientgotesting.PatchActionImpl{ makePatch(replaceCIPKeySourceWithoutOCIPatch), }, }, { Name: "ClusterImagePolicy with glob and KMS key, for invalid KMS key", Key: cipKMSName, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipKMSName, WithUID(uid), WithResourceVersion(resourceVersion), WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ KMS: "gcpkms://blah", }}, )), makeEmptyConfigMap(), // Make the existing configmap }, WantErr: true, WantPatches: []clientgotesting.PatchActionImpl{ patchFinalizers(system.Namespace(), cipKMSName), }, WantEvents: []string{ Eventf(corev1.EventTypeNormal, "FinalizerUpdate", `Updated "test-kms-cip" finalizers`), Eventf(corev1.EventTypeWarning, "InternalError", `kms specification should be in the format gcpkms://projects/[PROJECT_ID]/locations/[LOCATION]/keyRings/[KEY_RING]/cryptoKeys/[KEY]/cryptoKeyVersions/[VERSION]`), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipKMSName, WithUID(uid), WithResourceVersion(resourceVersion), WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Key: &v1alpha1.KeyRef{ KMS: "gcpkms://blah", }}, ), WithInitConditions, WithObservedGeneration(1), WithMarkInlineKeysFailed(`kms specification should be in the format gcpkms://projects/[PROJECT_ID]/locations/[LOCATION]/keyRings/[KEY_RING]/cryptoKeys/[KEY]/cryptoKeyVersions/[VERSION]`)), }}, }, { Name: "Keyless with match label selector", Key: testKey2, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName2, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithMatch(v1alpha1.MatchResource{ GroupVersionResource: metav1.GroupVersionResource{ Group: "apps", Version: "v1", Resource: "replicasets", }, ResourceSelector: &metav1.LabelSelector{ MatchLabels: map[string]string{"match": "match"}, }, }), WithAuthority(v1alpha1.Authority{ Keyless: &v1alpha1.KeylessRef{ CACert: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keylessSecretName, }}, Identities: placeholderIdentities, }}), ), makeConfigMapWithTwoEntries(), makeSecret(keylessSecretName, validPublicKeyData), }, WantPatches: []clientgotesting.PatchActionImpl{ makePatch(inlinedSecretKeylessMatchLabelsPatch), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipName2, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithMatch(v1alpha1.MatchResource{ GroupVersionResource: metav1.GroupVersionResource{ Group: "apps", Version: "v1", Resource: "replicasets", }, ResourceSelector: &metav1.LabelSelector{ MatchLabels: map[string]string{"match": "match"}, }, }), WithAuthority(v1alpha1.Authority{ Keyless: &v1alpha1.KeylessRef{ CACert: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keylessSecretName, }}, Identities: placeholderIdentities, }}), MarkReady), }}, PostConditions: []func(*testing.T, *TableRow){ AssertTrackingSecret(system.Namespace(), keylessSecretName), }, }, { Name: "Keyless with resource group and version selector", Key: testKey2, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName2, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithMatch(v1alpha1.MatchResource{ GroupVersionResource: metav1.GroupVersionResource{ Group: "apps", Version: "v1", Resource: "deployments", }, }), WithAuthority(v1alpha1.Authority{ Keyless: &v1alpha1.KeylessRef{ CACert: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keylessSecretName, }}, Identities: placeholderIdentities, }}), ), makeConfigMapWithTwoEntries(), makeSecret(keylessSecretName, validPublicKeyData), }, WantPatches: []clientgotesting.PatchActionImpl{ makePatch(inlinedSecretKeylessMatchResourcePatch), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipName2, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithMatch(v1alpha1.MatchResource{ GroupVersionResource: metav1.GroupVersionResource{ Group: "apps", Version: "v1", Resource: "deployments", }, }), WithAuthority(v1alpha1.Authority{ Keyless: &v1alpha1.KeylessRef{ CACert: &v1alpha1.KeyRef{ SecretRef: &corev1.SecretReference{ Name: keylessSecretName, }}, Identities: placeholderIdentities, }}), MarkReady), }}, PostConditions: []func(*testing.T, *TableRow){ AssertTrackingSecret(system.Namespace(), keylessSecretName), }, }, { Name: "Static with CIP level policy, configmapref exists, inlined", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Static: &v1alpha1.StaticRef{ Action: "pass", }}), WithPolicy(&v1alpha1.Policy{ Type: "cue", ConfigMapRef: &v1alpha1.ConfigMapReference{ Name: policyCMName, Key: policyCMKey, }, }), ), makeConfigMap(), makePolicyConfigMap(policyCMName, map[string]string{policyCMKey: testPolicy}), }, WantPatches: []clientgotesting.PatchActionImpl{ makePatch(inlinedPolicyPatch), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Static: &v1alpha1.StaticRef{ Action: "pass", }}), WithPolicy(&v1alpha1.Policy{ Type: "cue", ConfigMapRef: &v1alpha1.ConfigMapReference{ Name: policyCMName, Key: policyCMKey, }, }), MarkReady), }}, PostConditions: []func(*testing.T, *TableRow){ AssertTrackingConfigMap(system.Namespace(), policyCMName), }, }, { Name: "Static with CIP level policy, configmapref does not exist", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Static: &v1alpha1.StaticRef{ Action: "pass", }}), WithPolicy(&v1alpha1.Policy{ Type: "cue", ConfigMapRef: &v1alpha1.ConfigMapReference{ Name: policyCMName, Key: policyCMKey, }, }), ), makeConfigMap(), }, WantErr: true, WantPatches: []clientgotesting.PatchActionImpl{ makePatch(removeDataPatch), }, WantEvents: []string{ Eventf(corev1.EventTypeWarning, "InternalError", `configmap "policy-configmap" not found`), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Static: &v1alpha1.StaticRef{ Action: "pass", }}), WithPolicy(&v1alpha1.Policy{ Type: "cue", ConfigMapRef: &v1alpha1.ConfigMapReference{ Name: policyCMName, Key: policyCMKey, }, }), WithInitConditions, WithObservedGeneration(1), WithMarkInlineKeysOk, WithMarkInlinePoliciesFailed(`configmap "policy-configmap" not found`), ), }}, PostConditions: []func(*testing.T, *TableRow){ AssertTrackingConfigMap(system.Namespace(), policyCMName), }, }, { Name: "Static with CIP level URL policy, works", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Static: &v1alpha1.StaticRef{ Action: "pass", }}), WithPolicy(&v1alpha1.Policy{ Type: "cue", Remote: &v1alpha1.RemotePolicy{ URL: *policyURLGood, Sha256sum: testPolicySHA256, }, }), ), makeConfigMap(), }, WantErr: true, WantPatches: []clientgotesting.PatchActionImpl{ makePatch(inlinedPolicyPatch), }, WantEvents: []string{ Eventf(corev1.EventTypeWarning, "UpdateFailed", statusUpdateFailureMsg), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Static: &v1alpha1.StaticRef{ Action: "pass", }}), WithPolicy(&v1alpha1.Policy{ Type: "cue", Remote: &v1alpha1.RemotePolicy{ URL: *policyURLGood, Sha256sum: testPolicySHA256, }, }), MarkReady, ), }}, }, { Name: "Static with CIP level URL policy, SHA does not match", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Static: &v1alpha1.StaticRef{ Action: "pass", }}), WithPolicy(&v1alpha1.Policy{ Type: "cue", Remote: &v1alpha1.RemotePolicy{ URL: *policyURLGood, Sha256sum: testPolicySHA256Bad, }, }), ), makeConfigMap(), }, WantErr: true, WantPatches: []clientgotesting.PatchActionImpl{ makePatch(removeDataPatch), }, WantEvents: []string{ Eventf(corev1.EventTypeWarning, "UpdateFailed", statusUpdateFailureMsg), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewClusterImagePolicy(cipName, WithUID(uid), WithResourceVersion(resourceVersion), WithFinalizer, WithImagePattern(v1alpha1.ImagePattern{ Glob: glob, }), WithAuthority(v1alpha1.Authority{ Static: &v1alpha1.StaticRef{ Action: "pass", }}), WithPolicy(&v1alpha1.Policy{ Type: "cue", Remote: &v1alpha1.RemotePolicy{ URL: *policyURLGood, Sha256sum: testPolicySHA256Bad, }, }), WithInitConditions, WithObservedGeneration(1), WithMarkInlineKeysOk, WithMarkInlinePoliciesFailed(invalidSHAMsg), ), }}, }} logger := logtesting.TestLogger(t) table.Test(t, MakeFactory(func(ctx context.Context, listers *Listers, _ configmap.Watcher) controller.Reconciler { r := &Reconciler{ secretlister: listers.GetSecretLister(), configmaplister: listers.GetConfigMapLister(), kubeclient: fakekubeclient.Get(ctx), tracker: ctx.Value(TrackerKey).(tracker.Interface), } return clusterimagepolicy.NewReconciler(ctx, logger, fakecosignclient.Get(ctx), listers.GetClusterImagePolicyLister(), controller.GetEventRecorder(ctx), r) }, false, logger, privKMSKey, )) } func makeSecret(name, secret string) *corev1.Secret { return &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Namespace: system.Namespace(), Name: name, }, Data: map[string][]byte{ "publicKey": []byte(secret), }, } } func makePolicyConfigMap(name string, data map[string]string) *corev1.ConfigMap { return &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Namespace: system.Namespace(), Name: name, }, Data: data, } } func makeEmptyConfigMap() *corev1.ConfigMap { return &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Namespace: system.Namespace(), Name: config.ImagePoliciesConfigName, }, } } func makeConfigMap() *corev1.ConfigMap { return &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Namespace: system.Namespace(), Name: config.ImagePoliciesConfigName, }, Data: map[string]string{ cipName: `{"uid":"test-uid","resourceVersion":"0123456789","images":[{"glob":"ghcr.io/example/*"}],"authorities":[{"name":"authority-0","key":{"data":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J\nRCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ==\n-----END PUBLIC KEY-----","hashAlgorithm":"sha256"}}],"mode":"enforce"}`, }, } } func makeConfigMapWithWarn() *corev1.ConfigMap { return &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Namespace: system.Namespace(), Name: config.ImagePoliciesConfigName, }, Data: map[string]string{ cipName: `{"uid":"test-uid","resourceVersion":"0123456789","images":[{"glob":"ghcr.io/example/*"}],"authorities":[{"name":"authority-0","key":{"data":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J\nRCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ==\n-----END PUBLIC KEY-----","hashAlgorithm":"sha256"}}],"mode":"warn"}`, }, } } func patchKMS(ctx context.Context, t *testing.T, kmsKey, hashAlgorithm string) clientgotesting.PatchActionImpl { pubKey, err := getKMSPublicKey(ctx, kmsKey, hashAlgorithm) if err != nil { t.Fatalf("Failed to read KMS key ID %q: %v", kmsKey, err) } patch := `[{"op":"add","path":"/data","value":{"test-kms-cip":"{\"uid\":\"test-uid\",\"resourceVersion\":\"0123456789\",\"images\":[{\"glob\":\"ghcr.io/example/*\"}],\"authorities\":[{\"name\":\"authority-0\",\"key\":{\"data\":\"` + strings.ReplaceAll(pubKey, "\n", "\\\\n") + `\",\"hashAlgorithm\":\"` + hashAlgorithm + `\"}}],\"mode\":\"enforce\"}"}}]` return clientgotesting.PatchActionImpl{ ActionImpl: clientgotesting.ActionImpl{ Namespace: system.Namespace(), }, Name: config.ImagePoliciesConfigName, Patch: []byte(patch), } } // Same as above, just forcing an update by changing PUBLIC => NOTPUBLIC func makeDifferentConfigMap() *corev1.ConfigMap { return &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Namespace: system.Namespace(), Name: config.ImagePoliciesConfigName, }, Data: map[string]string{ cipName: `{"uid":"test-uid","resourceVersion":"0123456789", images":[{"glob":"ghcr.io/example/*"}],"authorities":[{"name":"authority-0","key":{"data":"-----BEGIN NOTPUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J\nRCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ==\n-----END NOTPUBLIC KEY-----"}}]}`, }, } } // Same as MakeConfigMap but a placeholder for second entry so we can remove it. func makeConfigMapWithTwoEntries() *corev1.ConfigMap { return &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Namespace: system.Namespace(), Name: config.ImagePoliciesConfigName, }, Data: map[string]string{ cipName: `{"images":[{"glob":"ghcr.io/example/*"}],"authorities":[{"name":"authority-0","key":{"data":"-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J\nRCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ==\n-----END PUBLIC KEY-----"}}],"mode":"enforce"}`, cipName2: "remove me please", }, } } func makePatch(patch string) clientgotesting.PatchActionImpl { return clientgotesting.PatchActionImpl{ ActionImpl: clientgotesting.ActionImpl{ Namespace: system.Namespace(), }, Name: config.ImagePoliciesConfigName, Patch: []byte(patch), } } func patchFinalizers(namespace, name string) clientgotesting.PatchActionImpl { action := clientgotesting.PatchActionImpl{} action.Name = name action.Namespace = namespace patch := `{"metadata":{"finalizers":["` + finalizerName + `"],"resourceVersion":"` + resourceVersion + `"}}` action.Patch = []byte(patch) return action } func patchRemoveFinalizers(namespace, name string) clientgotesting.PatchActionImpl { action := clientgotesting.PatchActionImpl{} action.Name = name action.Namespace = namespace patch := `{"metadata":{"finalizers":[],"resourceVersion":"` + resourceVersion + `"}}` action.Patch = []byte(patch) return action } ================================================ FILE: pkg/reconciler/clusterimagepolicy/controller.go ================================================ // 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. package clusterimagepolicy import ( "context" "time" corev1 "k8s.io/api/core/v1" "k8s.io/client-go/tools/cache" kubeclient "knative.dev/pkg/client/injection/kube/client" "knative.dev/pkg/configmap" "knative.dev/pkg/controller" "knative.dev/pkg/logging" // Use the informer factory that restricts only to our namespace. This way // we won't have to grant too broad RBAC rights, nor have trouble starting // up if we don't have them. pkgreconciler "knative.dev/pkg/reconciler" "knative.dev/pkg/system" "github.com/sigstore/policy-controller/pkg/apis/config" clusterimagepolicyinformer "github.com/sigstore/policy-controller/pkg/client/injection/informers/policy/v1alpha1/clusterimagepolicy" clusterimagepolicyreconciler "github.com/sigstore/policy-controller/pkg/client/injection/reconciler/policy/v1alpha1/clusterimagepolicy" cminformer "knative.dev/pkg/injection/clients/namespacedkube/informers/core/v1/configmap" secretinformer "knative.dev/pkg/injection/clients/namespacedkube/informers/core/v1/secret" ) // This is what the default finalizer name is, but make it explicit so we can // use it in tests as well. const finalizerName = "clusterimagepolicies.policy.sigstore.dev" type policyResyncPeriodKey struct{} // NewController creates a Reconciler and returns the result of NewImpl. func NewController( ctx context.Context, _ configmap.Watcher, ) *controller.Impl { clusterimagepolicyInformer := clusterimagepolicyinformer.Get(ctx) secretInformer := secretinformer.Get(ctx) configMapInformer := cminformer.Get(ctx) r := &Reconciler{ secretlister: secretInformer.Lister(), configmaplister: configMapInformer.Lister(), kubeclient: kubeclient.Get(ctx), } impl := clusterimagepolicyreconciler.NewImpl(ctx, r, func(_ *controller.Impl) controller.Options { return controller.Options{FinalizerName: finalizerName} }) r.tracker = impl.Tracker if _, err := clusterimagepolicyInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)); err != nil { logging.FromContext(ctx).Warnf("Failed clusterimagepolicyInformer AddEventHandler() %v", err) } if _, err := secretInformer.Informer().AddEventHandler(controller.HandleAll( // Call the tracker's OnChanged method, but we've seen the objects // coming through this path missing TypeMeta, so ensure it is properly // populated. controller.EnsureTypeMeta( r.tracker.OnChanged, corev1.SchemeGroupVersion.WithKind("Secret"), ), )); err != nil { logging.FromContext(ctx).Warnf("Failed secretInformer AddEventHandler() %v", err) } if _, err := configMapInformer.Informer().AddEventHandler(controller.HandleAll( // Call the tracker's OnChanged method, but we've seen the objects // coming through this path missing TypeMeta, so ensure it is properly // populated. controller.EnsureTypeMeta( r.tracker.OnChanged, corev1.SchemeGroupVersion.WithKind("ConfigMap"), ), )); err != nil { logging.FromContext(ctx).Warnf("Failed configMapInformer AddEventHandler() %v", err) } // When the underlying ConfigMap changes,perform a global resync on // ClusterImagePolicies to make sure their state is correctly reflected // in the ConfigMap. This is admittedly a bit heavy handed, but I don't // really see a way around it, since if something is wrong with the // ConfigMap but there are no changes to the ClusterImagePolicy, it needs // to be synced. grCb := func(_ interface{}) { logging.FromContext(ctx).Info("Doing a global resync on ClusterImagePolicies due to ConfigMap changing or resync period.") impl.GlobalResync(clusterimagepolicyInformer.Informer()) } // Resync on only ConfigMap changes that pertain to the one I care about // or after a resync period. // We could also fetch/construct the store and use CM watcher for it, but // since we need a lister for it anyways in the reconciler, just set up // the watch here. if _, err := configMapInformer.Informer().AddEventHandlerWithResyncPeriod(cache.FilteringResourceEventHandler{ FilterFunc: pkgreconciler.ChainFilterFuncs( pkgreconciler.NamespaceFilterFunc(system.Namespace()), pkgreconciler.NameFilterFunc(config.ImagePoliciesConfigName)), Handler: controller.HandleAll(grCb), }, FromContextOrDefaults(ctx)); err != nil { logging.FromContext(ctx).Warnf("Failed configMapInformer AddEventHandlerWithResyncPeriod() %v", err) } return impl } func ToContext(ctx context.Context, duration time.Duration) context.Context { return context.WithValue(ctx, policyResyncPeriodKey{}, duration) } // FromContextOrDefaults returns a stored policyResyncPeriod if attached. // If not found, it returns a default duration func FromContextOrDefaults(ctx context.Context) time.Duration { x, ok := ctx.Value(policyResyncPeriodKey{}).(time.Duration) if ok { return x } return controller.DefaultResyncPeriod } ================================================ FILE: pkg/reconciler/clusterimagepolicy/controller_test.go ================================================ // 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. package clusterimagepolicy import ( "testing" "time" "knative.dev/pkg/configmap" "knative.dev/pkg/controller" rtesting "knative.dev/pkg/reconciler/testing" // Fake injection informers _ "github.com/sigstore/policy-controller/pkg/client/injection/informers/policy/v1alpha1/clusterimagepolicy/fake" _ "knative.dev/pkg/client/injection/kube/informers/core/v1/configmap/fake" _ "knative.dev/pkg/injection/clients/namespacedkube/informers/core/v1/configmap/fake" _ "knative.dev/pkg/injection/clients/namespacedkube/informers/core/v1/secret/fake" _ "knative.dev/pkg/injection/clients/namespacedkube/informers/factory/fake" ) func TestNew(t *testing.T) { ctx, _ := rtesting.SetupFakeContext(t) c := NewController(ctx, &configmap.ManualWatcher{}) if c == nil { t.Fatal("Expected NewController to return a non-nil value") } } func TestContextDuration(t *testing.T) { ctx, _ := rtesting.SetupFakeContext(t) expected := controller.DefaultResyncPeriod actual := FromContextOrDefaults(ctx) if expected != actual { t.Fatal("Expected the context to store the value and be retrievable") } expected = time.Hour ctx = ToContext(ctx, expected) actual = FromContextOrDefaults(ctx) if expected != actual { t.Fatal("Expected the context to store the value and be retrievable") } } ================================================ FILE: pkg/reconciler/clusterimagepolicy/resources/configmap.go ================================================ // 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. package resources import ( "encoding/json" "fmt" webhookcip "github.com/sigstore/policy-controller/pkg/webhook/clusterimagepolicy" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/pkg/apis/duck" ) // NewConfigMap returns a new ConfigMap with an entry for the given // ClusterImagePolicy func NewConfigMap(ns, name, cipName string, cip *webhookcip.ClusterImagePolicy) (*corev1.ConfigMap, error) { entry, err := marshal(cip) if err != nil { return nil, err } cm := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Namespace: ns, Name: name, // TODO(vaikas): Set the ownerrefs. Don't want to keep adding one // for each CIP. }, Data: map[string]string{ cipName: entry, }, } return cm, nil } // CreatePatch updates a particular entry to see if they are differing and // returning the patch bytes for it that's suitable for calling // ConfigMap.Patch with. func CreatePatch(ns, name, cipName string, cm *corev1.ConfigMap, cip *webhookcip.ClusterImagePolicy) ([]byte, error) { //nolint: revive entry, err := marshal(cip) if err != nil { return nil, err } after := cm.DeepCopy() if after.Data == nil { after.Data = make(map[string]string) } after.Data[cipName] = entry jsonPatch, err := duck.CreatePatch(cm, after) if err != nil { return nil, fmt.Errorf("creating JSON patch: %w", err) } if len(jsonPatch) == 0 { return nil, nil } return jsonPatch.MarshalJSON() } // CreateRemovePatch removes an entry from the ConfigMap and returns the patch // bytes for it that's suitable for calling ConfigMap.Patch with. func CreateRemovePatch(ns, name string, cm *corev1.ConfigMap, cipName string) ([]byte, error) { //nolint: revive after := cm.DeepCopy() // Just remove it without checking if it exists. If it doesn't, then no // patch bytes are created. delete(after.Data, cipName) jsonPatch, err := duck.CreatePatch(cm, after) if err != nil { return nil, fmt.Errorf("creating JSON patch: %w", err) } if len(jsonPatch) == 0 { return nil, nil } return jsonPatch.MarshalJSON() } func marshal(spec *webhookcip.ClusterImagePolicy) (string, error) { bytes, err := json.Marshal(spec) if err != nil { return "", err } return string(bytes), nil } ================================================ FILE: pkg/reconciler/testing/v1alpha1/clusterimagepolicy.go ================================================ // 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. package testing import ( "context" "time" "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ) const finalizerName = "clusterimagepolicies.policy.sigstore.dev" // ClusterImagePolicyOption enables further configuration of a ClusterImagePolicy. type ClusterImagePolicyOption func(*v1alpha1.ClusterImagePolicy) // NewClusterImagePolicy creates a ClusterImagePolicy with ClusterImagePolicyOptions. func NewClusterImagePolicy(name string, o ...ClusterImagePolicyOption) *v1alpha1.ClusterImagePolicy { cip := &v1alpha1.ClusterImagePolicy{ ObjectMeta: metav1.ObjectMeta{ Name: name, Generation: 1, }, } for _, opt := range o { opt(cip) } cip.SetDefaults(context.Background()) return cip } func WithUID(uid string) ClusterImagePolicyOption { return func(cip *v1alpha1.ClusterImagePolicy) { cip.UID = types.UID(uid) } } func WithResourceVersion(resourceVersion string) ClusterImagePolicyOption { return func(cip *v1alpha1.ClusterImagePolicy) { cip.ResourceVersion = resourceVersion } } func WithClusterImagePolicyDeletionTimestamp(cip *v1alpha1.ClusterImagePolicy) { t := metav1.NewTime(time.Unix(1e9, 0)) cip.SetDeletionTimestamp(&t) } func WithImagePattern(ip v1alpha1.ImagePattern) ClusterImagePolicyOption { return func(cip *v1alpha1.ClusterImagePolicy) { cip.Spec.Images = append(cip.Spec.Images, ip) } } func WithAuthority(a v1alpha1.Authority) ClusterImagePolicyOption { return func(cip *v1alpha1.ClusterImagePolicy) { cip.Spec.Authorities = append(cip.Spec.Authorities, a) } } func WithPolicy(p *v1alpha1.Policy) ClusterImagePolicyOption { return func(cip *v1alpha1.ClusterImagePolicy) { cip.Spec.Policy = p } } func WithMatch(a v1alpha1.MatchResource) ClusterImagePolicyOption { return func(cip *v1alpha1.ClusterImagePolicy) { cip.Spec.Match = append(cip.Spec.Match, a) } } func WithMode(m string) ClusterImagePolicyOption { return func(cip *v1alpha1.ClusterImagePolicy) { cip.Spec.Mode = m } } func WithFinalizer(cip *v1alpha1.ClusterImagePolicy) { cip.Finalizers = []string{finalizerName} } func WithInitConditions(cip *v1alpha1.ClusterImagePolicy) { cip.Status.InitializeConditions() } func WithObservedGeneration(gen int64) ClusterImagePolicyOption { return func(cip *v1alpha1.ClusterImagePolicy) { cip.Status.ObservedGeneration = gen } } func MarkReady(cip *v1alpha1.ClusterImagePolicy) { WithInitConditions(cip) cip.Status.MarkInlineKeysOk() cip.Status.MarkInlinePoliciesOk() cip.Status.MarkCMUpdatedOK() cip.Status.ObservedGeneration = cip.Generation } func WithMarkInlineKeysOk(cip *v1alpha1.ClusterImagePolicy) { cip.Status.MarkInlineKeysOk() } func WithMarkInlineKeysFailed(msg string) ClusterImagePolicyOption { return func(cip *v1alpha1.ClusterImagePolicy) { cip.Status.MarkInlineKeysFailed(msg) } } func WithMarkInlinePoliciesOk(cip *v1alpha1.ClusterImagePolicy) { cip.Status.MarkInlinePoliciesOk() } func WithMarkInlinePoliciesFailed(msg string) ClusterImagePolicyOption { return func(cip *v1alpha1.ClusterImagePolicy) { cip.Status.MarkInlinePoliciesFailed(msg) } } func WithMarkCMUpdateFailed(msg string) ClusterImagePolicyOption { return func(cip *v1alpha1.ClusterImagePolicy) { cip.Status.MarkCMUpdateFailed(msg) } } ================================================ FILE: pkg/reconciler/testing/v1alpha1/factory.go ================================================ // 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. package testing import ( "context" "crypto/ecdsa" "encoding/json" "testing" corev1 "k8s.io/api/core/v1" "knative.dev/pkg/configmap" "knative.dev/pkg/logging" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/tools/record" "go.uber.org/zap" ktesting "k8s.io/client-go/testing" "knative.dev/pkg/controller" fakecosignclient "github.com/sigstore/policy-controller/pkg/client/injection/client/fake" fakekubeclient "knative.dev/pkg/client/injection/kube/client/fake" fakedynamicclient "knative.dev/pkg/injection/clients/dynamicclient/fake" "knative.dev/pkg/reconciler" reconcilertesting "knative.dev/pkg/reconciler/testing" fakekms "github.com/sigstore/sigstore/pkg/signature/kms/fake" ) const ( // maxEventBufferSize is the estimated max number of event notifications that // can be buffered during reconciliation. maxEventBufferSize = 10 ) // Ctor functions create a k8s controller with given params. type Ctor func(context.Context, *Listers, configmap.Watcher) controller.Reconciler // MakeFactory creates a reconciler factory with fake clients and controller created by `ctor`. func MakeFactory(ctor Ctor, unstructured bool, logger *zap.SugaredLogger, privKMSKey *ecdsa.PrivateKey) reconcilertesting.Factory { //nolint: revive return func(t *testing.T, r *reconcilertesting.TableRow) (controller.Reconciler, reconcilertesting.ActionRecorderList, reconcilertesting.EventList) { ls := NewListers(r.Objects) var ctx context.Context if r.Ctx != nil { ctx = r.Ctx } else { ctx = context.Background() } ctx = logging.WithLogger(ctx, logger) // Add private key for KMS testing ctx = context.WithValue(ctx, fakekms.KmsCtxKey{}, privKMSKey) ctx, kubeClient := fakekubeclient.With(ctx, ls.GetKubeObjects()...) ctx, client := fakecosignclient.With(ctx, ls.GetCosignObjects()...) ctx, dynamicClient := fakedynamicclient.With(ctx, NewScheme(), ToUnstructured(t, r.Objects)...) ctx = context.WithValue(ctx, TrackerKey, &reconcilertesting.FakeTracker{}) // The dynamic client's support for patching is BS. Implement it // here via PrependReactor (this can be overridden below by the // provided reactors). dynamicClient.PrependReactor("patch", "*", func(_ ktesting.Action) (bool, runtime.Object, error) { return true, nil, nil }) eventRecorder := record.NewFakeRecorder(maxEventBufferSize) ctx = controller.WithEventRecorder(ctx, eventRecorder) // Check the config maps in objects and add them to the fake cm watcher var cms []*corev1.ConfigMap for _, obj := range r.Objects { if cm, ok := obj.(*corev1.ConfigMap); ok { cms = append(cms, cm) } } configMapWatcher := configmap.NewStaticWatcher(cms...) // Set up our Controller from the fakes. c := ctor(ctx, &ls, configMapWatcher) r.Ctx = ctx // If the reconcilers is leader aware, then promote it. if la, ok := c.(reconciler.LeaderAware); ok { if la.Promote(reconciler.UniversalBucket(), func(reconciler.Bucket, types.NamespacedName) {}) != nil { panic("failed to leader promote") } } for _, reactor := range r.WithReactors { kubeClient.PrependReactor("*", "*", reactor) client.PrependReactor("*", "*", reactor) dynamicClient.PrependReactor("*", "*", reactor) } // Validate all Create and Update operations client.PrependReactor("create", "*", func(action ktesting.Action) (handled bool, ret runtime.Object, err error) { return reconcilertesting.ValidateCreates(ctx, action) }) client.PrependReactor("update", "*", func(action ktesting.Action) (handled bool, ret runtime.Object, err error) { return reconcilertesting.ValidateUpdates(ctx, action) }) actionRecorderList := reconcilertesting.ActionRecorderList{dynamicClient, client, kubeClient} eventList := reconcilertesting.EventList{Recorder: eventRecorder} return c, actionRecorderList, eventList } } // ToUnstructured takes a list of k8s resources and converts them to // Unstructured objects. // We must pass objects as Unstructured to the dynamic client fake, or it // won't handle them properly. func ToUnstructured(t *testing.T, objs []runtime.Object) (us []runtime.Object) { sch := NewScheme() for _, obj := range objs { obj = obj.DeepCopyObject() // Don't mess with the primary copy // Determine and set the TypeMeta for this object based on our test scheme. gvks, _, err := sch.ObjectKinds(obj) if err != nil { t.Fatal("Unable to determine kind for type:", err) } apiv, k := gvks[0].ToAPIVersionAndKind() ta, err := meta.TypeAccessor(obj) if err != nil { t.Fatal("Unable to create type accessor:", err) } ta.SetAPIVersion(apiv) ta.SetKind(k) b, err := json.Marshal(obj) if err != nil { t.Fatal("Unable to marshal:", err) } u := &unstructured.Unstructured{} if err := json.Unmarshal(b, u); err != nil { t.Fatal("Unable to unmarshal:", err) } us = append(us, u) } return } type key struct{} // TrackerKey is used to looking a FakeTracker in a context.Context var TrackerKey key = struct{}{} // AssertTrackingSecret will ensure the provided Secret is being tracked func AssertTrackingSecret(namespace, name string) func(*testing.T, *reconcilertesting.TableRow) { gvk := corev1.SchemeGroupVersion.WithKind("Secret") return AssertTrackingObject(gvk, namespace, name) } // AssertTrackingConfigMap will ensure the provided ConfigMap is being tracked func AssertTrackingConfigMap(namespace, name string) func(*testing.T, *reconcilertesting.TableRow) { gvk := corev1.SchemeGroupVersion.WithKind("ConfigMap") return AssertTrackingObject(gvk, namespace, name) } // AssertTrackingObject will ensure the following objects are being tracked func AssertTrackingObject(gvk schema.GroupVersionKind, namespace, name string) func(*testing.T, *reconcilertesting.TableRow) { apiVersion, kind := gvk.ToAPIVersionAndKind() return func(t *testing.T, r *reconcilertesting.TableRow) { tracker := r.Ctx.Value(TrackerKey).(*reconcilertesting.FakeTracker) refs := tracker.References() for _, ref := range refs { if ref.APIVersion == apiVersion && ref.Name == name && ref.Namespace == namespace && ref.Kind == kind { return } } t.Errorf("Object was not tracked - %s, Name=%s, Namespace=%s", gvk.String(), name, namespace) } } ================================================ FILE: pkg/reconciler/testing/v1alpha1/listers.go ================================================ // 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.package testing package testing import ( "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" fakecosignclientset "github.com/sigstore/policy-controller/pkg/client/clientset/versioned/fake" policylisters "github.com/sigstore/policy-controller/pkg/client/listers/policy/v1alpha1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" fakekubeclientset "k8s.io/client-go/kubernetes/fake" corev1listers "k8s.io/client-go/listers/core/v1" "k8s.io/client-go/tools/cache" "knative.dev/pkg/reconciler/testing" ) var clientSetSchemes = []func(*runtime.Scheme) error{ fakekubeclientset.AddToScheme, fakecosignclientset.AddToScheme, } type Listers struct { sorter testing.ObjectSorter } func NewScheme() *runtime.Scheme { scheme := runtime.NewScheme() for _, addTo := range clientSetSchemes { if addTo(scheme) != nil { panic("Failed to add to scheme") } } return scheme } func NewListers(objs []runtime.Object) Listers { scheme := runtime.NewScheme() for _, addTo := range clientSetSchemes { if addTo(scheme) != nil { panic("Failed to add to scheme") } } ls := Listers{ sorter: testing.NewObjectSorter(scheme), } ls.sorter.AddObjects(objs...) return ls } func (l *Listers) indexerFor(obj runtime.Object) cache.Indexer { return l.sorter.IndexerForObjectType(obj) } func (l *Listers) GetKubeObjects() []runtime.Object { return l.sorter.ObjectsForSchemeFunc(fakekubeclientset.AddToScheme) } func (l *Listers) GetCosignObjects() []runtime.Object { return l.sorter.ObjectsForSchemeFunc(fakecosignclientset.AddToScheme) } func (l *Listers) GetAllObjects() []runtime.Object { all := l.GetCosignObjects() all = append(all, l.GetKubeObjects()...) return all } func (l *Listers) GetClusterImagePolicyLister() policylisters.ClusterImagePolicyLister { return policylisters.NewClusterImagePolicyLister(l.indexerFor(&v1alpha1.ClusterImagePolicy{})) } func (l *Listers) GetTrustRootLister() policylisters.TrustRootLister { return policylisters.NewTrustRootLister(l.indexerFor(&v1alpha1.TrustRoot{})) } func (l *Listers) GetSecretLister() corev1listers.SecretLister { return corev1listers.NewSecretLister(l.indexerFor(&corev1.Secret{})) } func (l *Listers) GetConfigMapLister() corev1listers.ConfigMapLister { return corev1listers.NewConfigMapLister(l.indexerFor(&corev1.ConfigMap{})) } ================================================ FILE: pkg/reconciler/testing/v1alpha1/trustroot.go ================================================ // 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. package testing import ( "context" "time" "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "knative.dev/pkg/apis" ) const finalizerNameTrustRoot = "trustroots.policy.sigstore.dev" // TrustRootOption enables further configuration of a ClusterImagePolicy. type TrustRootOption func(*v1alpha1.TrustRoot) // NewTrustRoot creates a TrustRoot with TrustRootOptions. func NewTrustRoot(name string, o ...TrustRootOption) *v1alpha1.TrustRoot { tr := &v1alpha1.TrustRoot{ ObjectMeta: metav1.ObjectMeta{ Name: name, Generation: 1, }, } for _, opt := range o { opt(tr) } tr.SetDefaults(context.Background()) return tr } func WithTrustRootUID(uid string) TrustRootOption { return func(tr *v1alpha1.TrustRoot) { tr.UID = types.UID(uid) } } func WithTrustRootResourceVersion(resourceVersion string) TrustRootOption { return func(tr *v1alpha1.TrustRoot) { tr.ResourceVersion = resourceVersion } } func WithTrustRootDeletionTimestamp(tr *v1alpha1.TrustRoot) { t := metav1.NewTime(time.Unix(1e9, 0)) tr.SetDeletionTimestamp(&t) } func WithTrustRootFinalizer(tr *v1alpha1.TrustRoot) { tr.Finalizers = []string{finalizerNameTrustRoot} } // WithSigstoreKeys constructs a TrustRootOption which is suitable // for reconciler table driven testing. It hardcodes things like // organizations/common names, and URI/BaseURLs with predictable // values. func WithSigstoreKeys(sk map[string]string) TrustRootOption { return func(tr *v1alpha1.TrustRoot) { tr.Spec.SigstoreKeys = &v1alpha1.SigstoreKeys{ CertificateAuthorities: []v1alpha1.CertificateAuthority{{ Subject: v1alpha1.DistinguishedName{ Organization: "fulcio-organization", CommonName: "fulcio-common-name", }, URI: *apis.HTTPS("fulcio.example.com"), CertChain: []byte(sk["fulcio"]), }}, TLogs: []v1alpha1.TransparencyLogInstance{{ BaseURL: *apis.HTTPS("rekor.example.com"), HashAlgorithm: "sha-256", PublicKey: []byte(sk["rekor"]), }}, CTLogs: []v1alpha1.TransparencyLogInstance{{ BaseURL: *apis.HTTPS("ctfe.example.com"), HashAlgorithm: "sha-256", PublicKey: []byte(sk["ctfe"]), }}, TimeStampAuthorities: []v1alpha1.CertificateAuthority{{ Subject: v1alpha1.DistinguishedName{ Organization: "tsa-organization", CommonName: "tsa-common-name", }, URI: *apis.HTTPS("tsa.example.com"), CertChain: []byte(sk["tsa"]), }}, } } } // WithRepository constructs a TrustRootOption which is suitable // for reconciler table driven testing. func WithRepository(targets string, root, repository []byte, trustedRootTarget string) TrustRootOption { return func(tr *v1alpha1.TrustRoot) { tr.Spec.Repository = &v1alpha1.Repository{ Root: root, MirrorFS: repository, Targets: targets, TrustedRootTarget: trustedRootTarget, } } } func WithInitConditionsTrustRoot(tr *v1alpha1.TrustRoot) { tr.Status.InitializeConditions() } func WithObservedGenerationTrustRoot(gen int64) TrustRootOption { return func(tr *v1alpha1.TrustRoot) { tr.Status.ObservedGeneration = gen } } func MarkReadyTrustRoot(tr *v1alpha1.TrustRoot) { WithInitConditionsTrustRoot(tr) tr.Status.MarkInlineKeysOk() tr.Status.MarkCMUpdatedOK() tr.Status.ObservedGeneration = tr.Generation } func WithMarkInlineKeysOkTrustRoot(tr *v1alpha1.TrustRoot) { tr.Status.MarkInlineKeysOk() } func WithMarkInlineKeysFailedTrustRoot(msg string) TrustRootOption { return func(tr *v1alpha1.TrustRoot) { tr.Status.MarkInlineKeysFailed(msg) } } func WithMarkCMUpdateFailedTrustRoot(msg string) TrustRootOption { return func(tr *v1alpha1.TrustRoot) { tr.Status.MarkCMUpdateFailed(msg) } } ================================================ FILE: pkg/reconciler/trustroot/controller.go ================================================ // 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. package trustroot import ( "context" "k8s.io/client-go/tools/cache" kubeclient "knative.dev/pkg/client/injection/kube/client" "knative.dev/pkg/configmap" "knative.dev/pkg/controller" "knative.dev/pkg/logging" pkgreconciler "knative.dev/pkg/reconciler" "knative.dev/pkg/system" "github.com/sigstore/policy-controller/pkg/apis/config" trustrootinformer "github.com/sigstore/policy-controller/pkg/client/injection/informers/policy/v1alpha1/trustroot" trustrootreconciler "github.com/sigstore/policy-controller/pkg/client/injection/reconciler/policy/v1alpha1/trustroot" "github.com/sigstore/policy-controller/pkg/tuf" cminformer "knative.dev/pkg/injection/clients/namespacedkube/informers/core/v1/configmap" ) // This is what the default finalizer name is, but make it explicit so we can // use it in tests as well. const FinalizerName = "trustroots.policy.sigstore.dev" // NewController creates a Reconciler and returns the result of NewImpl. func NewController( ctx context.Context, _ configmap.Watcher, ) *controller.Impl { trustrootInformer := trustrootinformer.Get(ctx) configMapInformer := cminformer.Get(ctx) r := &Reconciler{ configmaplister: configMapInformer.Lister(), kubeclient: kubeclient.Get(ctx), } impl := trustrootreconciler.NewImpl(ctx, r, func(_ *controller.Impl) controller.Options { return controller.Options{FinalizerName: FinalizerName} }) if _, err := trustrootInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)); err != nil { logging.FromContext(ctx).Warnf("Failed trustrootInformer AddEventHandler() %v", err) } // When the underlying ConfigMap changes,perform a global resync on // TrustRoot to make sure their state is correctly reflected // in the ConfigMap. This is admittedly a bit heavy handed, but I don't // really see a way around it, since if something is wrong with the // ConfigMap but there are no changes to the TrustRoot, it needs // to be synced. grCb := func(_ interface{}) { logging.FromContext(ctx).Info("Doing a global resync on TrustRoot due to ConfigMap changing or resync period.") impl.GlobalResync(trustrootInformer.Informer()) } // Resync on only ConfigMap changes that pertain to the one I care about. // We could also fetch/construct the store and use CM watcher for it, but // since we need a lister for it anyways in the reconciler, just set up // the watch here. if _, err := configMapInformer.Informer().AddEventHandlerWithResyncPeriod(cache.FilteringResourceEventHandler{ FilterFunc: pkgreconciler.ChainFilterFuncs( pkgreconciler.NamespaceFilterFunc(system.Namespace()), pkgreconciler.NameFilterFunc(config.SigstoreKeysConfigName)), Handler: controller.HandleAll(grCb), }, tuf.FromContextOrDefaults(ctx)); err != nil { logging.FromContext(ctx).Warnf("Failed configMapInformer AddEventHandlerWithResyncPeriod() %v", err) } return impl } ================================================ FILE: pkg/reconciler/trustroot/controller_test.go ================================================ // 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. package trustroot import ( "testing" "knative.dev/pkg/configmap" rtesting "knative.dev/pkg/reconciler/testing" // Fake injection informers _ "github.com/sigstore/policy-controller/pkg/client/injection/informers/policy/v1alpha1/trustroot/fake" _ "knative.dev/pkg/client/injection/kube/informers/core/v1/configmap/fake" _ "knative.dev/pkg/injection/clients/namespacedkube/informers/core/v1/configmap/fake" _ "knative.dev/pkg/injection/clients/namespacedkube/informers/core/v1/secret/fake" _ "knative.dev/pkg/injection/clients/namespacedkube/informers/factory/fake" ) func TestNew(t *testing.T) { ctx, _ := rtesting.SetupFakeContext(t) c := NewController(ctx, &configmap.ManualWatcher{}) if c == nil { t.Fatal("Expected NewController to return a non-nil value") } } ================================================ FILE: pkg/reconciler/trustroot/resources/configmap.go ================================================ // 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. package resources import ( "fmt" "github.com/sigstore/policy-controller/pkg/apis/config" "google.golang.org/protobuf/encoding/protojson" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/pkg/apis/duck" ) // NewConfigMap returns a new ConfigMap with an entry for the given TrustRoot. func NewConfigMap(ns, name, trName string, sk *config.SigstoreKeys) (*corev1.ConfigMap, error) { entry, err := Marshal(sk) if err != nil { return nil, err } cm := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Namespace: ns, Name: name, }, Data: map[string]string{ trName: entry, }, } return cm, nil } // CreatePatch updates a particular entry to see if they are differing and // returning the patch bytes for it that's suitable for calling // ConfigMap.Patch with. func CreatePatch(ns, name, tkName string, cm *corev1.ConfigMap, sk *config.SigstoreKeys) ([]byte, error) { //nolint: revive entry, err := Marshal(sk) if err != nil { return nil, err } after := cm.DeepCopy() if after.Data == nil { after.Data = make(map[string]string) } after.Data[tkName] = entry jsonPatch, err := duck.CreatePatch(cm, after) if err != nil { return nil, fmt.Errorf("creating JSON patch: %w", err) } if len(jsonPatch) == 0 { return nil, nil } return jsonPatch.MarshalJSON() } // CreateRemovePatch removes an entry from the ConfigMap and returns the patch // bytes for it that's suitable for calling ConfigMap.Patch with. func CreateRemovePatch(ns, name string, cm *corev1.ConfigMap, tkName string) ([]byte, error) { //nolint: revive after := cm.DeepCopy() // Just remove it without checking if it exists. If it doesn't, then no // patch bytes are created. delete(after.Data, tkName) jsonPatch, err := duck.CreatePatch(cm, after) if err != nil { return nil, fmt.Errorf("creating JSON patch: %w", err) } if len(jsonPatch) == 0 { return nil, nil } return jsonPatch.MarshalJSON() } func Marshal(spec *config.SigstoreKeys) (string, error) { bytes, err := protojson.Marshal(spec) if err != nil { return "", err } return string(bytes), nil } ================================================ FILE: pkg/reconciler/trustroot/testdata/ctfeLogID.txt ================================================ d740b8dd64c961855e8953f4276369f184d833716a6a990844c923a9083d9296 ================================================ FILE: pkg/reconciler/trustroot/testdata/ctfePublicKey.pem ================================================ -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8CYN5Ck/g5tRZxuHcuTl8f8cp4Vn 31lziP9oJ2PbJd8bjWVaD4PDTLk6PVcPtiHtEeEN/JN1TtqQkUgsMlCfaw== -----END PUBLIC KEY----- ================================================ FILE: pkg/reconciler/trustroot/testdata/fulcioCert.pem ================================================ -----BEGIN CERTIFICATE----- MIIFwzCCA6ugAwIBAgIIfUmh4cIZr8QwDQYJKoZIhvcNAQELBQAwfjEMMAoGA1UE BhMDVVNBMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp c2NvMRYwFAYDVQQJEw01NDggTWFya2V0IFN0MQ4wDAYDVQQREwU1NzI3NDEZMBcG A1UEChMQTGludXggRm91bmRhdGlvbjAeFw0yMzEyMTQxODUxMzlaFw0yNDEyMTQx ODUxMzlaMH4xDDAKBgNVBAYTA1VTQTETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQG A1UEBxMNU2FuIEZyYW5jaXNjbzEWMBQGA1UECRMNNTQ4IE1hcmtldCBTdDEOMAwG A1UEERMFNTcyNzQxGTAXBgNVBAoTEExpbnV4IEZvdW5kYXRpb24wggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQDHVwB8bv84fUgVOqjjWtMAK4i5Zl93I9ai zh9S/qIuJNnKx1tA87xZcAuO5riq/kXA2fZGnnP4Vsp9VaVjK9o7+1QP2rFJ4p5r rQlZFovvrD1e6jEaoMc06v+YY4yl37b17W9sfd+5x5wZ0ArRjPAihpdVjYJwlqDR B0AlSo6Vq/aM9QejMG4CS1jXrEEUV8MwRNjyT2xdR4vkc6wj47A1/rknjCtMsieS eSmH/ZDamUGuUh5ej4/dmCiLw93Rou/yLlDcvAcFVzrrLMF/lRwUDUgoH1XDlpeC C1r5HB6jp1Huap9gcLNS3UCIZVpNDO0A3pjYaLBQ3bfHe6QxKuQcEd+VKqyP9SoP dNn31cygF28VR+k+0jU5uXxW7ilXrv7DVYMOcMNZCDA0BQdH/A3fO0ri+8t2Luo+ EilRWROBsJTuC28sesYc5NUUoszxVUoQFAhkxE6k5rGIzxO8XplgLjx0IPxU0wjj VhcBa7AKkAMT7gDrPXijhJbv7Q3QVkChOdj6VTPagCS+JtWBkzGvCNJmaIrbLdWF TtDMXfSSZoRyn/aXjQr/OFzBf6dDxJqEMvdD5T5Gg1sldZ00KLKqEx25i8HVZ8Xo V4jrZOH1b9nZa3DGZOPmditlqUppvJ7c6OIGqkpE1o8mcNKko/p0dCwcHQtXgIN5 76foyNG+twIDAQABo0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB /wIBATAdBgNVHQ4EFgQU6A9czPqMog/PFdvjxH3V/56BBhcwDQYJKoZIhvcNAQEL BQADggIBAAGqm7dJS+pNgCEUDE79S2r6c+BcH6DwTFvAujE0yvdTRdAVIo73CsqP W4cDFuCw2ekOhD17JUT+9PEGJv++u16X4tLHVI5QHPleU/qzZHSEIYt0AE+y9JEL R2RT0g11YToGzhIAto5OpOvBb1z+Q8uP5g4eK7Y8J2lVRkDk/62EtsaHTWgv9hJJ qsdwoUMVWxn/s0oanPjyGBMSwpoFDXX/k14NDsCGp7d2e5/DxjgYAenDTtnID3VK kvP46spBZ4yEbNIywjaubSXnNLsx2cY8Ypih23e8c1uQJ3O44FDYXVcqYZX9UOrK HS0aE5VpU5J/j2fr4hGE3SfRXXDizcZJcVWPL+k1DHKWlCREMYw12ha3Oe0uIlwK W7syTNnn8NgxxRgM4f83n0C/00CSqiTm8MYya3ue0m2gmCg6TguALbcIqZ3tEK3K vvNIbgxM0ZSePI8YktvtLTQsRK8bbianOht+CwYD2NnFKo68G0l57ByKXze0wG18 i943+NTOvU/Le+8SEwJ4asRld3v3L8pCpNAM7JX12zoqisAnCCj3hu6waA5XvMeh STj8yYtIxP1l1I1qfRJzMB9nGv9KzwmozHiw3oGJr/G3j1u1krrQfj4S6z16Bq29 nfILFnmk/MoeqYS6DBRY80b60289+R7CSCB5OQbQYvmjy/sxvcNO -----END CERTIFICATE----- ================================================ FILE: pkg/reconciler/trustroot/testdata/fulcioCertChain.pem ================================================ -----BEGIN CERTIFICATE----- MIIBPjCB5KADAgECAgECMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI2 MDExODA4MjQxMloXDTM2MDExODA4MjQxMlowDzENMAsGA1UEAxMEbGVhZjBZMBMG ByqGSM49AgEGCCqGSM49AwEHA0IABCnMX5oDLqAe/zsE5lxppdszsKB9svC/LhXU BLOk8T65kND9SyXG8MA1+SqW2Ic6YRnm5r2j+v/CRi6lGXs0GD6jMzAxMA4GA1Ud DwEB/wQEAwIGwDAfBgNVHSMEGDAWgBR3tK56OWKX6omj1P/kEWkvkiREpTAKBggq hkjOPQQDAgNJADBGAiEA9LiET+4DScPcPLP6IZqok40C7v3Pyo0FdUkYVC4RrdYC IQCRfJwlFjbw3HMQLNviY0CAhg8GAsMmsqFU/AJOlI8bgw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIBSTCB8aADAgECAgEBMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI2 MDExODA4MjQxMloXDTM2MDExODA4MjQxMlowDTELMAkGA1UEAxMCY2EwWTATBgcq hkjOPQIBBggqhkjOPQMBBwNCAARU9i+UOuHKRJslqkeIPM8Hvr/Onxo+rWaxEov1 xBE+vjXl/feFCmi38gAII5/UgqEVZlF5VBBdelEZB1i4ysbwo0IwQDAOBgNVHQ8B Af8EBAMCAgQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUd7Suejlil+qJo9T/ 5BFpL5IkRKUwCgYIKoZIzj0EAwIDRwAwRAIgaFt5RQfkYGl2tQyOX/9TfBci580r gnM/ECKeerqByKICIBvBOG3zfWB7qFUCosjgslm5aTxWLYblddNaKGbrjz99 -----END CERTIFICATE----- ================================================ FILE: pkg/reconciler/trustroot/testdata/marshalledEntry.json ================================================ { "mediaType": "application/vnd.dev.sigstore.trustedroot+json;version=0.1", "tlogs": [ { "baseUrl": "https://rekor.example.com", "hashAlgorithm": "SHA2_256", "publicKey": { "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdHzrblmwf4hME3+Ot7L2B8FkTd1RRfssnlhi2SyUyQY8OnpN6PjF6t7XdayNxJ7XYVWeLZA/G4Kg51QC7ybJ1g==", "keyDetails": "PKIX_ECDSA_P256_SHA_256", "validFor": { "start": "1970-01-01T00:00:00Z" } }, "logId": { "keyId": "M2E3ZWZjYTk3MGUzMGY2N2U2MTI0MzQ3MzZlMzVkNTRjMDYxZDM4OThlZmY1YjA2Mjc5ZmQ3MjIwNDM4OTY4NQ==" } } ], "certificateAuthorities": [ { "subject": { "organization": "fulcio-organization", "commonName": "fulcio-common-name" }, "uri": "https://fulcio.example.com", "certChain": { "certificates": [ { "rawBytes": "MIIBPjCB5KADAgECAgECMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI2MDExODA4MjQxMloXDTM2MDExODA4MjQxMlowDzENMAsGA1UEAxMEbGVhZjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCnMX5oDLqAe/zsE5lxppdszsKB9svC/LhXUBLOk8T65kND9SyXG8MA1+SqW2Ic6YRnm5r2j+v/CRi6lGXs0GD6jMzAxMA4GA1UdDwEB/wQEAwIGwDAfBgNVHSMEGDAWgBR3tK56OWKX6omj1P/kEWkvkiREpTAKBggqhkjOPQQDAgNJADBGAiEA9LiET+4DScPcPLP6IZqok40C7v3Pyo0FdUkYVC4RrdYCIQCRfJwlFjbw3HMQLNviY0CAhg8GAsMmsqFU/AJOlI8bgw==" }, { "rawBytes": "MIIBSTCB8aADAgECAgEBMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI2MDExODA4MjQxMloXDTM2MDExODA4MjQxMlowDTELMAkGA1UEAxMCY2EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARU9i+UOuHKRJslqkeIPM8Hvr/Onxo+rWaxEov1xBE+vjXl/feFCmi38gAII5/UgqEVZlF5VBBdelEZB1i4ysbwo0IwQDAOBgNVHQ8BAf8EBAMCAgQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUd7Suejlil+qJo9T/5BFpL5IkRKUwCgYIKoZIzj0EAwIDRwAwRAIgaFt5RQfkYGl2tQyOX/9TfBci580rgnM/ECKeerqByKICIBvBOG3zfWB7qFUCosjgslm5aTxWLYblddNaKGbrjz99" } ] }, "validFor": { "start": "1970-01-01T00:00:00Z" } } ], "ctlogs": [ { "baseUrl": "https://ctfe.example.com", "hashAlgorithm": "SHA2_256", "publicKey": { "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8CYN5Ck/g5tRZxuHcuTl8f8cp4Vn31lziP9oJ2PbJd8bjWVaD4PDTLk6PVcPtiHtEeEN/JN1TtqQkUgsMlCfaw==", "keyDetails": "PKIX_ECDSA_P256_SHA_256", "validFor": { "start": "1970-01-01T00:00:00Z" } }, "logId": { "keyId": "ZDc0MGI4ZGQ2NGM5NjE4NTVlODk1M2Y0Mjc2MzY5ZjE4NGQ4MzM3MTZhNmE5OTA4NDRjOTIzYTkwODNkOTI5Ng==" } } ], "timestampAuthorities": [ { "subject": { "organization": "tsa-organization", "commonName": "tsa-common-name" }, "uri": "https://tsa.example.com", "certChain": { "certificates": [ { "rawBytes": "MIIBOzCB5KADAgECAgECMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI2MDExODA4MjQxMloXDTM2MDExODA4MjQxMlowDzENMAsGA1UEAxMEbGVhZjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABHwOEW5q24H4uVDrH17YcWhI/LpzrOZzHCOkbQMU7IoLzpjgPydzaQWQp83vQdFai/OHe5vI7r+zKS1oyu675V+jMzAxMA4GA1UdDwEB/wQEAwIEEDAfBgNVHSMEGDAWgBTFKWL5YXMWOmTHuhZWTiocLIkMcTAKBggqhkjOPQQDAgNGADBDAiBTsXT0nv40DIsqkLmMFxWxsBm+0mkc+ySwXEEG3LbCEAIfGS/GLJZmABwvlAfjkvVZLuzyWA4uCX3hBK6ocqm8Dw==" }, { "rawBytes": "MIIBSTCB8aADAgECAgEBMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI2MDExODA4MjQxMloXDTM2MDExODA4MjQxMlowDTELMAkGA1UEAxMCY2EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARUAPrDDnECjXNrkWdfUsIt7ceI3XHMmBakiX0Z8wabBO9U2SdiS4qWE1QGIIcOxFVtnoOb2WQJSYW14C/I+ipyo0IwQDAOBgNVHQ8BAf8EBAMCAgQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUxSli+WFzFjpkx7oWVk4qHCyJDHEwCgYIKoZIzj0EAwIDRwAwRAIgdqkiRNmnW2fA9Fg6dG7ee0gQKP7MY/XSQo8vte++W/wCIFO9GS7HG4CIwb9nFfNw9zI8yW6Kqi4rClx2fRNNiMKy" } ] }, "validFor": { "start": "1970-01-01T00:00:00Z" } } ] } ================================================ FILE: pkg/reconciler/trustroot/testdata/marshalledEntryFromMirrorFS.json ================================================ { "tlogs": [ { "hashAlgorithm": "SHA2_256", "publicKey": { "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdHzrblmwf4hME3+Ot7L2B8FkTd1RRfssnlhi2SyUyQY8OnpN6PjF6t7XdayNxJ7XYVWeLZA/G4Kg51QC7ybJ1g==", "keyDetails": "PKIX_ECDSA_P256_SHA_256", "validFor": { "start": "1970-01-01T00:00:00Z" } }, "logId": { "keyId": "M2E3ZWZjYTk3MGUzMGY2N2U2MTI0MzQ3MzZlMzVkNTRjMDYxZDM4OThlZmY1YjA2Mjc5ZmQ3MjIwNDM4OTY4NQ==" } } ], "certificateAuthorities": [ { "certChain": { "certificates": [ { "rawBytes": "MIIBPjCB5KADAgECAgECMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI2MDExODA4MjQxMloXDTM2MDExODA4MjQxMlowDzENMAsGA1UEAxMEbGVhZjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCnMX5oDLqAe/zsE5lxppdszsKB9svC/LhXUBLOk8T65kND9SyXG8MA1+SqW2Ic6YRnm5r2j+v/CRi6lGXs0GD6jMzAxMA4GA1UdDwEB/wQEAwIGwDAfBgNVHSMEGDAWgBR3tK56OWKX6omj1P/kEWkvkiREpTAKBggqhkjOPQQDAgNJADBGAiEA9LiET+4DScPcPLP6IZqok40C7v3Pyo0FdUkYVC4RrdYCIQCRfJwlFjbw3HMQLNviY0CAhg8GAsMmsqFU/AJOlI8bgw==" }, { "rawBytes": "MIIBSTCB8aADAgECAgEBMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI2MDExODA4MjQxMloXDTM2MDExODA4MjQxMlowDTELMAkGA1UEAxMCY2EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARU9i+UOuHKRJslqkeIPM8Hvr/Onxo+rWaxEov1xBE+vjXl/feFCmi38gAII5/UgqEVZlF5VBBdelEZB1i4ysbwo0IwQDAOBgNVHQ8BAf8EBAMCAgQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUd7Suejlil+qJo9T/5BFpL5IkRKUwCgYIKoZIzj0EAwIDRwAwRAIgaFt5RQfkYGl2tQyOX/9TfBci580rgnM/ECKeerqByKICIBvBOG3zfWB7qFUCosjgslm5aTxWLYblddNaKGbrjz99" } ] }, "validFor": { "start": "1970-01-01T00:00:00Z" } } ], "ctlogs": [ { "hashAlgorithm": "SHA2_256", "publicKey": { "rawBytes": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8CYN5Ck/g5tRZxuHcuTl8f8cp4Vn31lziP9oJ2PbJd8bjWVaD4PDTLk6PVcPtiHtEeEN/JN1TtqQkUgsMlCfaw==", "keyDetails": "PKIX_ECDSA_P256_SHA_256", "validFor": { "start": "1970-01-01T00:00:00Z" } }, "logId": { "keyId": "ZDc0MGI4ZGQ2NGM5NjE4NTVlODk1M2Y0Mjc2MzY5ZjE4NGQ4MzM3MTZhNmE5OTA4NDRjOTIzYTkwODNkOTI5Ng==" } } ] } ================================================ FILE: pkg/reconciler/trustroot/testdata/rekorLogID.txt ================================================ 3a7efca970e30f67e612434736e35d54c061d3898eff5b06279fd72204389685 ================================================ FILE: pkg/reconciler/trustroot/testdata/rekorPublicKey.pem ================================================ -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdHzrblmwf4hME3+Ot7L2B8FkTd1R Rfssnlhi2SyUyQY8OnpN6PjF6t7XdayNxJ7XYVWeLZA/G4Kg51QC7ybJ1g== -----END PUBLIC KEY----- ================================================ FILE: pkg/reconciler/trustroot/testdata/root.json ================================================ { "signed": { "_type": "root", "spec_version": "1.0", "version": 1, "expires": "2026-07-18T08:24:13Z", "keys": { "0f052ad399560d75c43f80dd44fcf6a10c4971fba73517a063aab27140676628": { "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "01fbf6ed31f4a60f4ddc20684c9b6a62210f7cc81bf37c8abb2f18e2518a1c59" } }, "47f22c6ae82929f657e562ef5a5f7a44dab9f2a423ea60c963bef3f5a679a5b8": { "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "8ca04f921b74224e3c7b8fda0d8e1c0a40d29e9ddaa4068268c6e1e945fe7b33" } }, "98362a3b4a994284c5b72507d738ecdde8273e2cfe46639cbefec12d77ab3c81": { "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "b42259ceb0a929e7f0e34de7c6f1014562878c531f1cca89008862723f0604e3" } }, "b52e38b87fcd86befd146b05c90c021a8f8ac4c12f737e95488f5c4732e176be": { "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "666a150b3824c76d0b1fd12b4f078d56a413ebc7e52af27ea4143dc5fefe9ebd" } } }, "roles": { "root": { "keyids": [ "98362a3b4a994284c5b72507d738ecdde8273e2cfe46639cbefec12d77ab3c81" ], "threshold": 1 }, "snapshot": { "keyids": [ "b52e38b87fcd86befd146b05c90c021a8f8ac4c12f737e95488f5c4732e176be" ], "threshold": 1 }, "targets": { "keyids": [ "47f22c6ae82929f657e562ef5a5f7a44dab9f2a423ea60c963bef3f5a679a5b8" ], "threshold": 1 }, "timestamp": { "keyids": [ "0f052ad399560d75c43f80dd44fcf6a10c4971fba73517a063aab27140676628" ], "threshold": 1 } }, "consistent_snapshot": true }, "signatures": [ { "keyid": "98362a3b4a994284c5b72507d738ecdde8273e2cfe46639cbefec12d77ab3c81", "sig": "3222c66bcedf8bc6a9d0dc32d2fe5c8c8599dbfb8948a744a30a7e6bd628299b86674864446236a59e6742d2236e38c2b56f786b3d257db2e6ed2c2383c73405" } ] } ================================================ FILE: pkg/reconciler/trustroot/testdata/rootWithCustomTrustedRootJSON.json ================================================ { "signed": { "_type": "root", "spec_version": "1.0", "version": 1, "expires": "2026-07-18T08:24:13Z", "keys": { "09d76913304c807681f051c1f6a405e69dce88567987a9a05ef832619c37a515": { "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "c708835bb3f9da4e15246f1fe2bd6307c2bbdc790fa4dd706ab326737ecf18ac" } }, "98e2eb5de033b49093df9c572db565df0c419c6ee8f966ef283ede2b9605e3f6": { "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "2d412e542604beb9d3f8d3c6297db756ae7867ad464b04113223f6e296ae619c" } }, "99c6f2ed68ee12a1f79774e065c2aaf64926474903fc635df181c69354b42a45": { "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "a8074014766cd5e954d8fb0052c1d96a3ea24a8f57713f8b565bf59738fbd930" } }, "ef4513aee940067b6e65576b145c78bf4e4b0578937ac90a5988fad0015aa7d2": { "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "f5843909df3a7ee84bceda784a600f533d5068f0a4d8386dd0e4af385e761aeb" } } }, "roles": { "root": { "keyids": [ "98e2eb5de033b49093df9c572db565df0c419c6ee8f966ef283ede2b9605e3f6" ], "threshold": 1 }, "snapshot": { "keyids": [ "99c6f2ed68ee12a1f79774e065c2aaf64926474903fc635df181c69354b42a45" ], "threshold": 1 }, "targets": { "keyids": [ "ef4513aee940067b6e65576b145c78bf4e4b0578937ac90a5988fad0015aa7d2" ], "threshold": 1 }, "timestamp": { "keyids": [ "09d76913304c807681f051c1f6a405e69dce88567987a9a05ef832619c37a515" ], "threshold": 1 } }, "consistent_snapshot": true }, "signatures": [ { "keyid": "98e2eb5de033b49093df9c572db565df0c419c6ee8f966ef283ede2b9605e3f6", "sig": "03f03fab4f85f76889ab26fb1c7c9e062c9bc1deb0682f892930d1ab5b8754027d1fc68ea4525288d75215b52908ac409e4d31f4978a239adef46e5143a8030a" } ] } ================================================ FILE: pkg/reconciler/trustroot/testdata/rootWithTrustedRootJSON.json ================================================ { "signed": { "_type": "root", "spec_version": "1.0", "version": 1, "expires": "2026-07-18T08:24:13Z", "keys": { "3148238dd2571a8ab01d2f7ca1dcbd2ef39a2d8a8ac4e119239619ecd7f64073": { "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "0b28494b749a5ae017b322c8523e24495bc7f50033447f510932aef2858d4932" } }, "37c1f6aac7da789076c751c18a47136aff269196076faa48fb990923a0489882": { "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "7c0b12362a6238bf8894aa2bf7b1f4c12c8c2060eeeaff9be9ad46c599210b65" } }, "a967817408b2856cbaca2df5504d1632a7a50898daf5f1c8a9aa5e061ffd3556": { "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "aa1f6ee30b54597b7b18fe40d29abde301cf3cf7bbfab15e5b326be465f20293" } }, "b75ab36dcd12107f9f22fe6438e0653ca9053bb98d94db85f1be0468d5a46974": { "keytype": "ed25519", "scheme": "ed25519", "keyid_hash_algorithms": [ "sha256", "sha512" ], "keyval": { "public": "aefcc8af52bdb4c46cf00521d74e4fce5579ac74be43f3bf0079b5e1f6d7fbc8" } } }, "roles": { "root": { "keyids": [ "3148238dd2571a8ab01d2f7ca1dcbd2ef39a2d8a8ac4e119239619ecd7f64073" ], "threshold": 1 }, "snapshot": { "keyids": [ "a967817408b2856cbaca2df5504d1632a7a50898daf5f1c8a9aa5e061ffd3556" ], "threshold": 1 }, "targets": { "keyids": [ "b75ab36dcd12107f9f22fe6438e0653ca9053bb98d94db85f1be0468d5a46974" ], "threshold": 1 }, "timestamp": { "keyids": [ "37c1f6aac7da789076c751c18a47136aff269196076faa48fb990923a0489882" ], "threshold": 1 } }, "consistent_snapshot": true }, "signatures": [ { "keyid": "3148238dd2571a8ab01d2f7ca1dcbd2ef39a2d8a8ac4e119239619ecd7f64073", "sig": "7fc9e6ee840c2b617a6feb54d9896769f50c51a6b01fece37f4417a1fab379fb523f1f48632076693af6b04f7e736a5e9ee8a9673c4294f2735749ddd456ab0c" } ] } ================================================ FILE: pkg/reconciler/trustroot/testdata/testdata.go ================================================ // 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. // // Package testdata contains test data for the trustroot reconciler. To // regenerate, run `make generate-testdata` from the root of the repository. package testdata import ( "embed" ) //go:embed * var FS embed.FS func Get(filename string) []byte { file, err := FS.ReadFile(filename) if err != nil { panic(err) } return file } ================================================ FILE: pkg/reconciler/trustroot/testdata/tsaCertChain.pem ================================================ -----BEGIN CERTIFICATE----- MIIBOzCB5KADAgECAgECMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI2 MDExODA4MjQxMloXDTM2MDExODA4MjQxMlowDzENMAsGA1UEAxMEbGVhZjBZMBMG ByqGSM49AgEGCCqGSM49AwEHA0IABHwOEW5q24H4uVDrH17YcWhI/LpzrOZzHCOk bQMU7IoLzpjgPydzaQWQp83vQdFai/OHe5vI7r+zKS1oyu675V+jMzAxMA4GA1Ud DwEB/wQEAwIEEDAfBgNVHSMEGDAWgBTFKWL5YXMWOmTHuhZWTiocLIkMcTAKBggq hkjOPQQDAgNGADBDAiBTsXT0nv40DIsqkLmMFxWxsBm+0mkc+ySwXEEG3LbCEAIf GS/GLJZmABwvlAfjkvVZLuzyWA4uCX3hBK6ocqm8Dw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIBSTCB8aADAgECAgEBMAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAmNhMB4XDTI2 MDExODA4MjQxMloXDTM2MDExODA4MjQxMlowDTELMAkGA1UEAxMCY2EwWTATBgcq hkjOPQIBBggqhkjOPQMBBwNCAARUAPrDDnECjXNrkWdfUsIt7ceI3XHMmBakiX0Z 8wabBO9U2SdiS4qWE1QGIIcOxFVtnoOb2WQJSYW14C/I+ipyo0IwQDAOBgNVHQ8B Af8EBAMCAgQwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUxSli+WFzFjpkx7oW Vk4qHCyJDHEwCgYIKoZIzj0EAwIDRwAwRAIgdqkiRNmnW2fA9Fg6dG7ee0gQKP7M Y/XSQo8vte++W/wCIFO9GS7HG4CIwb9nFfNw9zI8yW6Kqi4rClx2fRNNiMKy -----END CERTIFICATE----- ================================================ FILE: pkg/reconciler/trustroot/trustroot.go ================================================ // 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. package trustroot import ( "context" "crypto" "crypto/ecdsa" "encoding/json" "errors" "fmt" "strings" "github.com/sigstore/cosign/v3/pkg/cosign" "github.com/sigstore/policy-controller/pkg/apis/config" "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" trustrootreconciler "github.com/sigstore/policy-controller/pkg/client/injection/reconciler/policy/v1alpha1/trustroot" "github.com/sigstore/policy-controller/pkg/reconciler/trustroot/resources" "github.com/sigstore/policy-controller/pkg/tuf" pbcommon "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" "github.com/sigstore/sigstore/pkg/cryptoutils" sigstoretuf "github.com/sigstore/sigstore/pkg/tuf" "google.golang.org/protobuf/encoding/protojson" corev1 "k8s.io/api/core/v1" apierrs "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" corev1listers "k8s.io/client-go/listers/core/v1" "knative.dev/pkg/logging" "knative.dev/pkg/reconciler" "knative.dev/pkg/system" ) // Reconciler implements ConfigMap reconciler. // TrustRoot resources. type Reconciler struct { configmaplister corev1listers.ConfigMapLister kubeclient kubernetes.Interface } // Check that our Reconciler implements Interface as well as finalizer var _ trustrootreconciler.Interface = (*Reconciler)(nil) var _ trustrootreconciler.Finalizer = (*Reconciler)(nil) // ReconcileKind implements Interface.ReconcileKind. func (r *Reconciler) ReconcileKind(ctx context.Context, trustroot *v1alpha1.TrustRoot) reconciler.Event { trustroot.Status.InitializeConditions() var sigstoreKeys *config.SigstoreKeys var err error switch { case trustroot.Spec.Repository != nil: sigstoreKeys, err = r.getSigstoreKeysFromMirrorFS(ctx, trustroot.Spec.Repository) case trustroot.Spec.Remote != nil: sigstoreKeys, err = r.getSigstoreKeysFromRemote(ctx, trustroot.Spec.Remote) case trustroot.Spec.SigstoreKeys != nil: sigstoreKeys, err = config.ConvertSigstoreKeys(ctx, trustroot.Spec.SigstoreKeys) default: // This should not happen since the CRD has been validated. err = fmt.Errorf("invalid TrustRoot entry: %s missing repository,remote, and sigstoreKeys", trustroot.Name) logging.FromContext(ctx).Errorf("Invalid trustroot entry: %s missing repository,remote, and sigstoreKeys", trustroot.Name) } if err != nil { logging.FromContext(ctx).Errorf("Failed to get Sigstore Keys: %v", err) trustroot.Status.MarkInlineKeysFailed(err.Error()) return err } trustroot.Status.MarkInlineKeysOk() // LogIDs for Rekor get created from the PublicKey, so we need to construct // them before serializing. // Note this is identical to what we do with CTLog PublicKeys, but they // are not restricted to being only ecdsa.PublicKey. for i, tlog := range sigstoreKeys.Tlogs { pk, logID, err := pemToKeyAndID(config.SerializePublicKey(tlog.PublicKey)) if err != nil { return fmt.Errorf("invalid rekor public key %d: %w", i, err) } // This needs to be ecdsa instead of crypto.PublicKey // https://github.com/sigstore/cosign/issues/2540 _, ok := pk.(*ecdsa.PublicKey) if !ok { return fmt.Errorf("public key %d is not ecdsa.PublicKey", i) } sigstoreKeys.Tlogs[i].LogId = &config.LogID{KeyId: []byte(logID)} } for i, ctlog := range sigstoreKeys.Ctlogs { _, logID, err := pemToKeyAndID(config.SerializePublicKey(ctlog.PublicKey)) if err != nil { return fmt.Errorf("invalid ctlog public key %d: %w", i, err) } sigstoreKeys.Ctlogs[i].LogId = &config.LogID{KeyId: []byte(logID)} } // See if the CM holding configs exists existing, err := r.configmaplister.ConfigMaps(system.Namespace()).Get(config.SigstoreKeysConfigName) if err != nil { if !apierrs.IsNotFound(err) { logging.FromContext(ctx).Errorf("Failed to get configmap: %v", err) trustroot.Status.MarkCMUpdateFailed(err.Error()) return err } // Does not exist, create it. cm, err := resources.NewConfigMap(system.Namespace(), config.SigstoreKeysConfigName, trustroot.Name, sigstoreKeys) if err != nil { logging.FromContext(ctx).Errorf("Failed to construct configmap: %v", err) trustroot.Status.MarkCMUpdateFailed(err.Error()) return err } _, err = r.kubeclient.CoreV1().ConfigMaps(system.Namespace()).Create(ctx, cm, metav1.CreateOptions{}) if err != nil { trustroot.Status.MarkCMUpdateFailed(err.Error()) return err } trustroot.Status.MarkCMUpdatedOK() return nil } // Check if we need to update the configmap or not. patchBytes, err := resources.CreatePatch(system.Namespace(), config.SigstoreKeysConfigName, trustroot.Name, existing.DeepCopy(), sigstoreKeys) if err != nil { logging.FromContext(ctx).Errorf("Failed to construct patch: %v", err) trustroot.Status.MarkCMUpdateFailed(err.Error()) return err } if len(patchBytes) > 0 { _, err = r.kubeclient.CoreV1().ConfigMaps(system.Namespace()).Patch(ctx, config.SigstoreKeysConfigName, types.JSONPatchType, patchBytes, metav1.PatchOptions{}) if err != nil { logging.FromContext(ctx).Errorf("Failed to patch: %v", err) trustroot.Status.MarkCMUpdateFailed(err.Error()) return err } } trustroot.Status.MarkCMUpdatedOK() return nil } // FinalizeKind implements Interface.ReconcileKind. func (r *Reconciler) FinalizeKind(ctx context.Context, trustroot *v1alpha1.TrustRoot) reconciler.Event { // See if the CM holding configs even exists existing, err := r.configmaplister.ConfigMaps(system.Namespace()).Get(config.SigstoreKeysConfigName) if err != nil { if !apierrs.IsNotFound(err) { // There's very little we can do here. This could happen if it's // intermittent error, which is fine when we retry. But if something // goofy happens like we lost access to it, then it's a bit of a // pickle since the entry will exist there and we can't remove it. // So keep trying. Other option would be just to bail. logging.FromContext(ctx).Errorf("Failed to get configmap: %v", err) return err } // Since the CM doesn't exist, there's nothing for us to clean up. return nil } // TrustRoot exists, so remove our entry from it. return r.removeTrustRootEntry(ctx, existing, trustroot.Name) } // getSigstoreKeys will take a TUF Repository specification, and fetch the // necessary Keys / Certificates from there for Fulcio, Rekor, and CTLog. func (r *Reconciler) getSigstoreKeysFromMirrorFS(ctx context.Context, repository *v1alpha1.Repository) (*config.SigstoreKeys, error) { tufClient, err := tuf.ClientFromSerializedMirror(ctx, repository.MirrorFS, repository.Root, repository.Targets, v1alpha1.DefaultTUFRepoPrefix) if err != nil { return nil, fmt.Errorf("failed to construct TUF client from mirror: %w", err) } trustedRootTarget := "trusted_root.json" if repository.TrustedRootTarget != "" { trustedRootTarget = repository.TrustedRootTarget } return GetSigstoreKeysFromTuf(ctx, tufClient, trustedRootTarget) } func (r *Reconciler) getSigstoreKeysFromRemote(ctx context.Context, remote *v1alpha1.Remote) (*config.SigstoreKeys, error) { tufClient, err := tuf.ClientFromRemote(ctx, remote.Mirror.String(), remote.Root, remote.Targets) if err != nil { return nil, fmt.Errorf("failed to construct TUF client from remote: %w", err) } trustedRootTarget := "trusted_root.json" if remote.TrustedRootTarget != "" { trustedRootTarget = remote.TrustedRootTarget } return GetSigstoreKeysFromTuf(ctx, tufClient, trustedRootTarget) } // remoteTrustRootEntry removes a TrustRoot entry from a CM. If no entry exists, it's a nop. func (r *Reconciler) removeTrustRootEntry(ctx context.Context, cm *corev1.ConfigMap, trustrootName string) error { patchBytes, err := resources.CreateRemovePatch(system.Namespace(), config.SigstoreKeysConfigName, cm.DeepCopy(), trustrootName) if err != nil { logging.FromContext(ctx).Errorf("Failed to create remove patch: %v", err) return err } if len(patchBytes) > 0 { _, err = r.kubeclient.CoreV1().ConfigMaps(system.Namespace()).Patch(ctx, config.SigstoreKeysConfigName, types.JSONPatchType, patchBytes, metav1.PatchOptions{}) return err } return nil } // pemToKeyAndID takes a public key in PEM format, and turns it into // crypto.PublicKey and the CTLog LogId. func pemToKeyAndID(pem []byte) (crypto.PublicKey, string, error) { pk, err := cryptoutils.UnmarshalPEMToPublicKey(pem) if err != nil { return nil, "", fmt.Errorf("unmarshaling PEM public key: %w", err) } logID, err := cosign.GetTransparencyLogID(pk) if err != nil { return nil, "", fmt.Errorf("failed to construct LogID for rekor: %w", err) } return pk, logID, nil } // These are private to sigstore/sigstore even though I don't think they should // be. type customMetadata struct { Usage sigstoretuf.UsageKind `json:"usage"` Status sigstoretuf.StatusKind `json:"status"` URI string `json:"uri"` } type sigstoreCustomMetadata struct { Sigstore customMetadata `json:"sigstore"` } // GetSigstoreKeysFromTuf returns the sigstore keys from the TUF updater. Note // that this should really be exposed from the sigstore/sigstore TUF pkg, but // is currently not. func GetSigstoreKeysFromTuf(ctx context.Context, tufClient *tuf.TUFClient, trustedRootTarget string) (*config.SigstoreKeys, error) { ret := &config.SigstoreKeys{} // Try to get the trusted root target using GetTarget, which correctly // traverses TUF delegations (unlike GetTopLevelTargets). data, err := tufClient.GetTarget(trustedRootTarget) if err == nil { if err := protojson.Unmarshal(data, ret); err != nil { return nil, fmt.Errorf("parsing %s: %w", trustedRootTarget, err) } return ret, nil } // Only fall back to legacy path if the target was not found. // Other errors (network, hash mismatch, etc.) should be propagated. if !strings.Contains(err.Error(), "not found") { return nil, fmt.Errorf("fetching %s: %w", trustedRootTarget, err) } // Fall back to using custom metadata on top-level targets (e.g. for // older private TUF repositories that don't have trusted_root.json). targets, err := tufClient.GetTopLevelTargets() if err != nil { return nil, fmt.Errorf("getting top-level targets: %w", err) } for name, targetMeta := range targets { // Skip any targets that do not include custom metadata. if targetMeta.Custom == nil { continue } var scm sigstoreCustomMetadata err := json.Unmarshal(*targetMeta.Custom, &scm) if err != nil { logging.FromContext(ctx).Warnf("Custom metadata not configured properly for target %s, skipping target: %v", name, err) continue } data, err := tufClient.GetTarget(name) if err != nil { return nil, fmt.Errorf("downloading target %s: %w", name, err) } switch scm.Sigstore.Usage { case sigstoretuf.Fulcio: certChain, err := config.DeserializeCertChain(data) if err != nil { return nil, fmt.Errorf("deserializing certificate chain: %w", err) } ret.CertificateAuthorities = append(ret.CertificateAuthorities, &config.CertificateAuthority{ Uri: scm.Sigstore.URI, CertChain: certChain, ValidFor: &config.TimeRange{ Start: &config.Timestamp{}, }, }, ) case sigstoretuf.CTFE: tlog, err := genTransparencyLogInstance(scm.Sigstore.URI, data) if err != nil { return nil, fmt.Errorf("creating transparency log instance: %w", err) } ret.Ctlogs = append(ret.Ctlogs, tlog) case sigstoretuf.Rekor: tlog, err := genTransparencyLogInstance(scm.Sigstore.URI, data) if err != nil { return nil, fmt.Errorf("creating transparency log instance: %w", err) } ret.Tlogs = append(ret.Tlogs, tlog) } } // Make sure there's at least a single CertificateAuthority (Fulcio there). // Some others could be optional. if len(ret.CertificateAuthorities) == 0 { return nil, errors.New("no certificate authorities found") } return ret, nil } func genTransparencyLogInstance(baseURL string, pkBytes []byte) (*config.TransparencyLogInstance, error) { pbpk, pk, err := config.DeserializePublicKey(pkBytes) if err != nil { return nil, fmt.Errorf("unmarshaling PEM public key: %w", err) } logID, err := cosign.GetTransparencyLogID(pk) if err != nil { return nil, fmt.Errorf("failed to construct LogID: %w", err) } return &config.TransparencyLogInstance{ BaseUrl: baseURL, HashAlgorithm: pbcommon.HashAlgorithm_SHA2_256, PublicKey: pbpk, LogId: &pbcommon.LogId{KeyId: []byte(logID)}, }, nil } ================================================ FILE: pkg/reconciler/trustroot/trustroot_test.go ================================================ // 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. package trustroot import ( "bytes" "context" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/x509" "crypto/x509/pkix" _ "embed" "encoding/pem" "fmt" "math/big" "strings" "testing" "time" "google.golang.org/protobuf/encoding/protojson" "knative.dev/pkg/apis" logtesting "knative.dev/pkg/logging/testing" "github.com/sigstore/policy-controller/pkg/apis/config" "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" fakecosignclient "github.com/sigstore/policy-controller/pkg/client/injection/client/fake" "github.com/sigstore/policy-controller/pkg/client/injection/reconciler/policy/v1alpha1/trustroot" pbcommon "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" clientgotesting "k8s.io/client-go/testing" fakekubeclient "knative.dev/pkg/client/injection/kube/client/fake" "knative.dev/pkg/configmap" "knative.dev/pkg/controller" "knative.dev/pkg/system" . "github.com/sigstore/policy-controller/pkg/reconciler/testing/v1alpha1" "github.com/sigstore/policy-controller/pkg/reconciler/trustroot/resources" "github.com/sigstore/policy-controller/pkg/reconciler/trustroot/testdata" . "knative.dev/pkg/reconciler/testing" _ "knative.dev/pkg/system/testing" ) const ( trName = "test-trustroot" testKey = "test-trustroot" tkName2 = "test-trustroot-2" testKey2 = "test-trustroot-2" resourceVersion = "0123456789" uid = "test-uid" uid2 = "test-uid-2" // These are the public keys from an airgapped TUF repository. /* TODO(vaikas): Uncomment and test these make the roundtrip tufCTFE = `-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJvCJi707fv5tMJ1U2TVMZ+uO4dKG aEcvjlCkgBCKXbrkumZV0m0dSlK1V1gxEiyQ8y6hk1MxJNe2AZrZUt7a4w== -----END PUBLIC KEY----- ` tufFulcio = `-----BEGIN CERTIFICATE----- MIIFwzCCA6ugAwIBAgIIK7xb+rqY4gEwDQYJKoZIhvcNAQELBQAwfjEMMAoGA1UE BhMDVVNBMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp c2NvMRYwFAYDVQQJEw01NDggTWFya2V0IFN0MQ4wDAYDVQQREwU1NzI3NDEZMBcG A1UEChMQTGludXggRm91bmRhdGlvbjAeFw0yMjEyMDgwMjE3NTFaFw0yMzEyMDgw MjE3NTFaMH4xDDAKBgNVBAYTA1VTQTETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQG A1UEBxMNU2FuIEZyYW5jaXNjbzEWMBQGA1UECRMNNTQ4IE1hcmtldCBTdDEOMAwG A1UEERMFNTcyNzQxGTAXBgNVBAoTEExpbnV4IEZvdW5kYXRpb24wggIiMA0GCSqG SIb3DQEBAQUAA4ICDwAwggIKAoICAQC142Ejlg2QxIwpNjbaeW/ft9sH1TXU6CWg bsvVp77vRgckSnpM3RTC/gwEwJHtX+GOTrP9ro6nFJN3G3hcFnaMHLKdGrof9iHu /w/lZLwQzXzVT+0ZyZxytHAWGFBvmYM4J33jH6Dj9PvqONwtSBSmZBPc/H/8EvYs UzxPWukhOtotSH3VXDqZ4jl96MLe0+5g2Wi7MxRX44X1RiPS14ba1ES538bThhcQ 4SMj3uhbdsCIkcm7eF4EY3pEXQpXEEGnZGfwYgQr+6cT07Zd/WDM0NX3KxH6qRk9 gDjPnfcMuFbOTbfD/nuvx6FNX6OUrzrZSglkLvcPIBVOW7Ln41LAb7aXmbWLFEJn uLooPpYYr+6NhnFDNGpsBKGKr/kvbQyDKKst3CKj9otPS1363ni41qnoA7YWSqxw z4185dKKc+Y7yvJQsRlr6qG1sNLO+c77fSS5VZImzNozBcRkuLJFlX+WB0uzgQU5 s45IZW+fK92nfu8MmKjzHR+idyr4OyjS0YSN3GMgc0UP7K6hVphLedApFpykBSFG UgiPZwrT+mGSVgmOXq5n1dQTCD14lEh2qt3/rff8zNc0CMANWybaMGBGQ4bhVVXe RKYx9u2PZjPv53p7Yb/DCdqnGEDw/HCBDiCs4oYe4daE36xUojxDSm3DaeNG68z9 RL7gfUjAxQIDAQABo0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB /wIBATAdBgNVHQ4EFgQUf+lbNX0Wh4h+Q0SRthRK+KfLjqEwDQYJKoZIhvcNAQEL BQADggIBAEhJja0ZSKwXcaOXCYRXTE06+JbpezI5LevBhmbRQK789Rq10JeAXa7m EToRGlGFLH2uDT11msFKyM3v67KlE1SYVcqKmClYfIVEYH3La0uI+9rHZnWgb4Bl y1B8wblKJzhYQD9Z4H/gs+BAsoRX5VoFyIgkNBk1p3ftaVCbkQvS0OYtYs5iw4eK cI71/IsTIT3Zppj9R8IGsqwLKgzfnyNcFJdz+ohc6V22PjZMEBHCsHPO4av2LlWK 5Y1flL+2bqTqbmO/bjfX0w4Z1DuojRcOZF7SH4O3Qu2Y7/69gH7Cp0niVCm5z+S5 011V6PvMjrmiE+xVkxLHbYEgocbFhd5DciMCXpvsuDZojaI3FREmBqiIhKoki3rb wuElya78bMwkZ1krp76nWso47/0+51io/WriAdr0cjmzonho7RqIE3DC77CEMkag ZvKSmL3sff+WNSrnPlznK19NA2z4ImW9MszqPrCTQGP//BBu7SamzofVM9f4PAIr FTpnW6sGdpCzP8E0WUu9B+viKrtfM/9sxnI9WhfJPdrEP0iZW3vhwvgQbKb5D2OS U4nrVov6BWr/BnhQK8IXo1tq3j8FCRIoleXNhks4gnkOaDsW2KtVqwtK3iO3BvPb L5w0gdLjwMLkek72y61Xqz5WxZwNhl5YcmBKuSvmVSHvA68BVSbB -----END CERTIFICATE----- ` tufRekor = `-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEenlW+tMJ9ymhl858kKiD14CC06x9 r36rTqTSiLYrdl2ZVE3mOD/KcbyBZM1/RHVKx/g1r3d0YSoVCKbF4DAvcQ== -----END PUBLIC KEY----- ` */ // Just some formatting strings that make it easier to construct patches // to config map. replacePatchFmtString = `[{"op":"replace","path":"/data/%s","value":"%s"}]` removePatchFmtString = `[{"op":"remove","path":"/data/%s"}]` ) // testmap with prepopulated entries for creating TrustRoot resource. // ctfe => CTLog Public Key // fulcio => CertificateAuthority certificate // rekor => TLog PublicKey // tsa => TimeStampAuthorities certificate chain (root, intermediate, leaf) var sigstoreKeys = map[string]string{ "ctfe": string(testdata.Get("ctfePublicKey.pem")), "fulcio": string(testdata.Get("fulcioCertChain.pem")), "rekor": string(testdata.Get("rekorPublicKey.pem")), "tsa": string(testdata.Get("tsaCertChain.pem")), } // canonicalizeSigstoreKeys round-trips the SigstoreKeys through protojson so // the output is deterministic for the current test run. This is necessary // because protojson has "randomly deterministic" output, meaning it will add // whitespace randomly depending on the digest of the executable. // See https://go-review.googlesource.com/c/protobuf/+/151340 and // https://github.com/golang/protobuf/issues/1121 func canonicalizeSigstoreKeys(in []byte) []byte { keys := &config.SigstoreKeys{} err := protojson.Unmarshal(in, keys) if err != nil { panic(err) } out, err := protojson.Marshal(keys) if err != nil { panic(err) } return out } // This is the marshalled entry from above keys/certs with fixed values // (for ease of testing) for other parts. var marshalledEntry = string(canonicalizeSigstoreKeys(testdata.Get("marshalledEntry.json"))) // this is the marshalled entry for when we construct from the repository. var marshalledEntryFromMirrorFS = string(canonicalizeSigstoreKeys(testdata.Get("marshalledEntryFromMirrorFS.json"))) var rekorLogID = string(testdata.Get("rekorLogID.txt")) var ctfeLogID = string(testdata.Get("ctfeLogID.txt")) // validRepository is a valid tarred repository representing an air-gap // TUF repository. var validRepository = testdata.Get("tufRepo.tar") // IMPORTANT: The next expiration is on 2025-03-02 // rootJSON is a valid root.json for above TUF repository. var rootJSON = testdata.Get("root.json") // validRepositoryWithTrustedRootJSON is a valid tarred repository representing // an air-gap TUF repository containing trusted_root.json. var validRepositoryWithTrustedRootJSON = testdata.Get("tufRepoWithTrustedRootJSON.tar") // IMPORTANT: The next expiration is on 2025-03-02 // rootJSON is a valid root.json for above TUF repository. var rootWithTrustedRootJSON = testdata.Get("rootWithTrustedRootJSON.json") // validRepositoryWithCustomTrustedRootJSON is a valid tarred repository representing // an air-gap TUF repository containing custom_trusted_root.json. var validRepositoryWithCustomTrustedRootJSON = testdata.Get("tufRepoWithCustomTrustedRootJSON.tar") // rootWithCustomTrustedRootJSON is a valid root.json for above TUF repository. var rootWithCustomTrustedRootJSON = testdata.Get("rootWithCustomTrustedRootJSON.json") func TestReconcile(t *testing.T) { table := TableTest{{ Name: "bad workqueue key", // Make sure Reconcile handles bad keys. Key: "too/many/parts", }, { Name: "key not found", // Make sure Reconcile handles good keys that don't exist. Key: "foo/not-found", }, { Name: "TrustRoot not found", Key: testKey, }, { Name: "TrustRoot is being deleted, doesn't exist, no changes", Key: testKey, Objects: []runtime.Object{ NewTrustRoot(trName, WithTrustRootDeletionTimestamp), }, }, { Name: "TrustRoot with SigstoreKeys, cm created and finalizer", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewTrustRoot(trName, WithTrustRootUID(uid), WithTrustRootResourceVersion(resourceVersion), WithSigstoreKeys(sigstoreKeys), )}, WantCreates: []runtime.Object{ makeConfigMapWithSigstoreKeys(), }, WantPatches: []clientgotesting.PatchActionImpl{ patchFinalizers(system.Namespace(), trName), }, WantEvents: []string{ Eventf(corev1.EventTypeNormal, "FinalizerUpdate", `Updated "test-trustroot" finalizers`), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewTrustRoot(trName, WithTrustRootUID(uid), WithTrustRootResourceVersion(resourceVersion), WithSigstoreKeys(sigstoreKeys), MarkReadyTrustRoot, )}}, }, { Name: "TrustRoot with SigstoreKeys, cm exists with entry, no changes", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewTrustRoot(trName, WithTrustRootUID(uid), WithTrustRootResourceVersion(resourceVersion), WithSigstoreKeys(sigstoreKeys), ), makeConfigMapWithSigstoreKeys(), }, WantPatches: []clientgotesting.PatchActionImpl{ patchFinalizers(system.Namespace(), trName), }, WantEvents: []string{ Eventf(corev1.EventTypeNormal, "FinalizerUpdate", `Updated "test-trustroot" finalizers`), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewTrustRoot(trName, WithTrustRootUID(uid), WithTrustRootResourceVersion(resourceVersion), WithSigstoreKeys(sigstoreKeys), MarkReadyTrustRoot, )}}, }, { Name: "TrustRoot with SigstoreKeys, cm exists with different, replace patched", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewTrustRoot(trName, WithTrustRootUID(uid), WithTrustRootResourceVersion(resourceVersion), WithSigstoreKeys(sigstoreKeys), WithTrustRootFinalizer, ), makeDifferentConfigMap(), }, WantPatches: []clientgotesting.PatchActionImpl{ makePatch(replacePatchFmtString, trName, marshalledEntry), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewTrustRoot(trName, WithTrustRootUID(uid), WithTrustRootResourceVersion(resourceVersion), WithSigstoreKeys(sigstoreKeys), WithTrustRootFinalizer, MarkReadyTrustRoot, )}}, }, { Name: "TrustRoot with SigstoreKeys, cm exists with different, replace patched but fails", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewTrustRoot(trName, WithTrustRootUID(uid), WithTrustRootResourceVersion(resourceVersion), WithSigstoreKeys(sigstoreKeys), WithTrustRootFinalizer, ), makeDifferentConfigMap(), }, WantPatches: []clientgotesting.PatchActionImpl{ makePatch(replacePatchFmtString, trName, marshalledEntry), }, WithReactors: []clientgotesting.ReactionFunc{ InduceFailure("patch", "configmaps"), }, WantErr: true, WantEvents: []string{ Eventf(corev1.EventTypeWarning, "InternalError", "inducing failure for patch configmaps"), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewTrustRoot(trName, WithTrustRootUID(uid), WithTrustRootResourceVersion(resourceVersion), WithSigstoreKeys(sigstoreKeys), WithTrustRootFinalizer, WithInitConditionsTrustRoot, WithObservedGenerationTrustRoot(1), WithMarkInlineKeysOkTrustRoot, WithMarkCMUpdateFailedTrustRoot("inducing failure for patch configmaps"), )}}, }, { Name: "Two SigstoreKeys, one deleted, verify it is removed", Key: testKey2, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewTrustRoot(trName, WithTrustRootUID(uid), WithTrustRootResourceVersion(resourceVersion), WithSigstoreKeys(sigstoreKeys), WithTrustRootFinalizer, ), NewTrustRoot(tkName2, WithTrustRootUID(uid2), WithTrustRootResourceVersion(resourceVersion), WithSigstoreKeys(sigstoreKeys), WithTrustRootFinalizer, WithTrustRootDeletionTimestamp, ), makeConfigMapWithTwoEntries(), }, WantPatches: []clientgotesting.PatchActionImpl{ patchRemoveFinalizers(system.Namespace(), testKey2), makeRemovePatch(tkName2), }, WantEvents: []string{ Eventf(corev1.EventTypeNormal, "FinalizerUpdate", `Updated "test-trustroot-2" finalizers`), }, }, { Name: "With repository", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewTrustRoot(trName, WithTrustRootUID(uid), WithTrustRootResourceVersion(resourceVersion), WithRepository("targets", rootJSON, validRepository, ""), WithTrustRootFinalizer, ), }, WantCreates: []runtime.Object{ makeConfigMapWithMirrorFS(marshalledEntryFromMirrorFS), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewTrustRoot(trName, WithTrustRootUID(uid), WithTrustRootResourceVersion(resourceVersion), WithRepository("targets", rootJSON, validRepository, ""), WithTrustRootFinalizer, MarkReadyTrustRoot, )}}, }, { Name: "With repository containing trusted_root.json", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewTrustRoot(trName, WithTrustRootUID(uid), WithTrustRootResourceVersion(resourceVersion), WithRepository("targets", rootWithTrustedRootJSON, validRepositoryWithTrustedRootJSON, ""), WithTrustRootFinalizer, ), }, WantCreates: []runtime.Object{ makeConfigMapWithMirrorFS(marshalledEntry), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewTrustRoot(trName, WithTrustRootUID(uid), WithTrustRootResourceVersion(resourceVersion), WithRepository("targets", rootWithTrustedRootJSON, validRepositoryWithTrustedRootJSON, ""), WithTrustRootFinalizer, MarkReadyTrustRoot, )}}, }, { Name: "With repository containing custom_trusted_root.json", Key: testKey, SkipNamespaceValidation: true, // Cluster scoped Objects: []runtime.Object{ NewTrustRoot(trName, WithTrustRootUID(uid), WithTrustRootResourceVersion(resourceVersion), WithRepository("targets", rootWithCustomTrustedRootJSON, validRepositoryWithCustomTrustedRootJSON, "custom_trusted_root.json"), WithTrustRootFinalizer, ), }, WantCreates: []runtime.Object{ makeConfigMapWithMirrorFS(marshalledEntry), }, WantStatusUpdates: []clientgotesting.UpdateActionImpl{{ Object: NewTrustRoot(trName, WithTrustRootUID(uid), WithTrustRootResourceVersion(resourceVersion), WithRepository("targets", rootWithCustomTrustedRootJSON, validRepositoryWithCustomTrustedRootJSON, "custom_trusted_root.json"), WithTrustRootFinalizer, MarkReadyTrustRoot, )}}, }} logger := logtesting.TestLogger(t) table.Test(t, MakeFactory(func(ctx context.Context, listers *Listers, _ configmap.Watcher) controller.Reconciler { r := &Reconciler{ configmaplister: listers.GetConfigMapLister(), kubeclient: fakekubeclient.Get(ctx), } return trustroot.NewReconciler(ctx, logger, fakecosignclient.Get(ctx), listers.GetTrustRootLister(), controller.GetEventRecorder(ctx), r) }, false, logger, nil, // Only meaningful for CIP reconciler, but reuse the same factory. )) } func makeConfigMapWithSigstoreKeys() *corev1.ConfigMap { ret := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Namespace: system.Namespace(), Name: config.SigstoreKeysConfigName, }, Data: make(map[string]string), } source := NewTrustRoot(trName, WithSigstoreKeys(sigstoreKeys)) c, err := config.ConvertSigstoreKeys(context.Background(), source.Spec.SigstoreKeys) if err != nil { panic("failed to convert test SigstoreKeys") } for i := range c.Tlogs { c.Tlogs[i].LogId = &config.LogID{KeyId: []byte(rekorLogID)} } for i := range c.Ctlogs { c.Ctlogs[i].LogId = &config.LogID{KeyId: []byte(ctfeLogID)} } marshalled, err := resources.Marshal(c) if err != nil { panic("failed to marshal test SigstoreKeys") } ret.Data[trName] = marshalled return ret } func makeConfigMapWithMirrorFS(entry string) *corev1.ConfigMap { return &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Namespace: system.Namespace(), Name: config.SigstoreKeysConfigName, }, Data: map[string]string{"test-trustroot": entry}, } } // Same as above, just forcing an update because the entry in the configMap // is not what we expect, it doesn't really matter what it is. func makeDifferentConfigMap() *corev1.ConfigMap { return &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Namespace: system.Namespace(), Name: config.SigstoreKeysConfigName, }, Data: map[string]string{ trName: `{"uid":"test-uid","resourceVersion":"0123456789", images":[{"glob":"ghcr.io/example/*"}],"authorities":[{"name":"authority-0","key":{"data":"-----BEGIN NOTPUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExB6+H6054/W1SJgs5JR6AJr6J35J\nRCTfQ5s1kD+hGMSE1rH7s46hmXEeyhnlRnaGF8eMU/SBJE/2NKPnxE7WzQ==\n-----END NOTPUBLIC KEY-----"}}]}`, }, } } // Same as MakeConfigMap but a placeholder for second entry so we can remove it. func makeConfigMapWithTwoEntries() *corev1.ConfigMap { return &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ Namespace: system.Namespace(), Name: config.SigstoreKeysConfigName, }, Data: map[string]string{ trName: marshalledEntry, tkName2: "remove me please", }, } } // makePatch makes a patch that one would be able to patch ConfigMap with. // fmtstr defines the ops/targets, key is the actual key the operation is // in the configmap. patch is the unescape quoted (for ease of readability in // constants) that will then be escaped before creating the patch. func makePatch(fmtstr, key, patch string) clientgotesting.PatchActionImpl { escapedPatch := strings.ReplaceAll(patch, "\"", "\\\"") out := fmt.Sprintf(fmtstr, key, escapedPatch) return clientgotesting.PatchActionImpl{ ActionImpl: clientgotesting.ActionImpl{ Namespace: system.Namespace(), }, Name: config.SigstoreKeysConfigName, Patch: []byte(out), } } // makeRemovePatch makes a patch suitable for removing from a configmap. func makeRemovePatch(key string) clientgotesting.PatchActionImpl { return clientgotesting.PatchActionImpl{ ActionImpl: clientgotesting.ActionImpl{ Namespace: system.Namespace(), }, Name: config.SigstoreKeysConfigName, Patch: []byte(fmt.Sprintf(removePatchFmtString, key)), } } func patchFinalizers(namespace, name string) clientgotesting.PatchActionImpl { action := clientgotesting.PatchActionImpl{} action.Name = name action.Namespace = namespace patch := `{"metadata":{"finalizers":["` + FinalizerName + `"],"resourceVersion":"` + resourceVersion + `"}}` action.Patch = []byte(patch) return action } func patchRemoveFinalizers(namespace, name string) clientgotesting.PatchActionImpl { action := clientgotesting.PatchActionImpl{} action.Name = name action.Namespace = namespace patch := `{"metadata":{"finalizers":[],"resourceVersion":"` + resourceVersion + `"}}` action.Patch = []byte(patch) return action } // TestConvertSigstoreKeys tests marshalling / unmarshalling to the configmap and back. // This is here instead of in the pkg/apis/config because of import cycles and // having both types v1alpha1.SigstoreTypes and config.SigstoreTypes being // available makes testing way easier, and due to import cycles we can't put // that in config and yet import v1alpha1. func TestConvertSigstoreKeys(t *testing.T) { itemsPerEntry := 2 type key struct { pem []byte der []byte } type testTlog struct { url string hashAlgorithm string publicKey key } type testCA struct { url string org string commonName string certChain []key } type testData struct { tlogs []testTlog ctlogs []testTlog cas []testCA tsas []testCA } hashAlgorithms := []string{"sha-256", "sha-512"} hashAlgorithmMap := map[string]pbcommon.HashAlgorithm{"sha-256": pbcommon.HashAlgorithm_SHA2_256, "sha-512": pbcommon.HashAlgorithm_SHA2_512} test := testData{} // construct test data for i := 0; i < itemsPerEntry; i++ { for _, service := range []string{"tlog", "ctlog"} { priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatalf("failed to generate ecdsa key: %v", err) } der, err := x509.MarshalPKIXPublicKey(priv.Public().(*ecdsa.PublicKey)) if err != nil { t.Fatalf("failed to marshal ecdsa key: %v", err) } pem := pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: der}) tlog := testTlog{ url: fmt.Sprintf("https://%s-%d.example.com", service, i), hashAlgorithm: hashAlgorithms[i%2], publicKey: key{pem, der}, } switch service { case "tlog": test.tlogs = append(test.tlogs, tlog) case "ctlog": test.ctlogs = append(test.ctlogs, tlog) } } for _, service := range []string{"fulcio", "tsa"} { priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatalf("failed to generate ecdsa key: %v", err) } template := x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{ CommonName: "Test Certificate", }, NotBefore: time.Now(), NotAfter: time.Now().AddDate(1, 0, 0), KeyUsage: x509.KeyUsageDigitalSignature, BasicConstraintsValid: true, } der, err := x509.CreateCertificate(rand.Reader, &template, &template, priv.Public(), priv) if err != nil { t.Fatalf("failed to create x509 certificate: %v", err) } pem := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der}) ca := testCA{ url: fmt.Sprintf("https://%s-%d.example.com", service, i), org: fmt.Sprintf("Test Org %d for %s", i, service), commonName: fmt.Sprintf("Test CA %d for %s", i, service), certChain: []key{{pem, der}}, } switch service { case "fulcio": test.cas = append(test.cas, ca) case "tsa": test.tsas = append(test.tsas, ca) } } } // create and populate source source := v1alpha1.SigstoreKeys{} for _, tlog := range test.tlogs { url, err := apis.ParseURL(tlog.url) if err != nil { t.Fatalf("failed to parse url: %v", err) } source.TLogs = append(source.TLogs, v1alpha1.TransparencyLogInstance{ BaseURL: *url, HashAlgorithm: tlog.hashAlgorithm, PublicKey: tlog.publicKey.pem, }) } for _, ctlog := range test.ctlogs { url, err := apis.ParseURL(ctlog.url) if err != nil { t.Fatalf("failed to parse url: %v", err) } source.CTLogs = append(source.CTLogs, v1alpha1.TransparencyLogInstance{ BaseURL: *url, HashAlgorithm: ctlog.hashAlgorithm, PublicKey: ctlog.publicKey.pem, }) } for _, ca := range test.cas { url, err := apis.ParseURL(ca.url) if err != nil { t.Fatalf("failed to parse url: %v", err) } source.CertificateAuthorities = append(source.CertificateAuthorities, v1alpha1.CertificateAuthority{ Subject: v1alpha1.DistinguishedName{ Organization: ca.org, CommonName: ca.commonName, }, URI: *url, CertChain: ca.certChain[0].pem, }) } for _, tsa := range test.tsas { url, err := apis.ParseURL(tsa.url) if err != nil { t.Fatalf("failed to parse url: %v", err) } source.TimeStampAuthorities = append(source.TimeStampAuthorities, v1alpha1.CertificateAuthority{ Subject: v1alpha1.DistinguishedName{ Organization: tsa.org, CommonName: tsa.commonName, }, URI: *url, CertChain: tsa.certChain[0].pem, }) } // convert from v1alpha1 to config and let's marshal to configmap and back // to make sure we exercise the path from: // v1alpha1 => config => configMap => back (this is what reconciler will // use to call cosign verification functions with). converted, err := config.ConvertSigstoreKeys(context.Background(), &source) if err != nil { t.Fatalf("Failed to convert entry: %v", err) } marshalled, err := resources.Marshal(converted) if err != nil { t.Fatalf("Failed to marshal entry: %v", err) } tkMap := map[string]string{"test-entry": marshalled} skMap, err := config.NewSigstoreKeysFromMap(tkMap) if err != nil { t.Fatalf("Failed to construct from map entry: %v", err) } sk := skMap.SigstoreKeys["test-entry"] if len(sk.Tlogs) != 2 { t.Errorf("Not enough TLog entries, want 2 got %d", len(sk.Tlogs)) } if len(sk.Ctlogs) != 2 { t.Errorf("Not enough CTLog entries, want 2 got %d", len(sk.Ctlogs)) } if len(sk.CertificateAuthorities) != 2 { t.Errorf("Not enough CertificateAuthority entries, want 2 got %d", len(sk.CertificateAuthorities)) } if len(sk.TimestampAuthorities) != 2 { t.Errorf("Not enough TimestampAuthorities entries, want 2 got %d", len(sk.TimestampAuthorities)) } // Verify TLog, CTLog for i := 0; i < itemsPerEntry; i++ { for _, service := range []string{"tlog", "ctlog"} { var entry *config.TransparencyLogInstance var tlog testTlog switch service { case "tlog": entry = sk.Tlogs[i] tlog = test.tlogs[i] case "ctlog": entry = sk.Ctlogs[i] tlog = test.ctlogs[i] default: panic("invalid type") } if entry.BaseUrl != tlog.url { t.Errorf("Unexpected BaseUrl for %s %d wanted %s got %s", service, i, tlog.url, entry.BaseUrl) } if entry.HashAlgorithm != hashAlgorithmMap[tlog.hashAlgorithm] { t.Errorf("Unexpected HashAlgorithm for %s %d wanted %s got %s", service, i, tlog.hashAlgorithm, entry.HashAlgorithm) } if !bytes.Equal(entry.PublicKey.RawBytes, tlog.publicKey.der) { t.Errorf("Unexpected PublicKey for %s %d wanted %s got %s", service, i, tlog.publicKey.der, entry.PublicKey.RawBytes) } } } // Verify CertificateAuthority, TimestampAuthorities for i := 0; i < itemsPerEntry; i++ { for _, prefix := range []string{"fulcio", "tsa"} { var entry *config.CertificateAuthority var ca testCA switch prefix { case "fulcio": entry = sk.CertificateAuthorities[i] ca = test.cas[i] case "tsa": entry = sk.TimestampAuthorities[i] ca = test.tsas[i] default: panic("invalid type") } if entry.Uri != ca.url { t.Errorf("Unexpected Uri for %s %d wanted %s got %s", prefix, i, ca.url, entry.Uri) } if entry.Subject.Organization != ca.org { t.Errorf("Unexpected Organization for %s %d wanted %s got %s", prefix, i, ca.org, entry.Subject.Organization) } if entry.Subject.CommonName != ca.commonName { t.Errorf("Unexpected CommonName for %s %d wanted %s got %s", prefix, i, ca.commonName, entry.Subject.CommonName) } if !bytes.Equal(entry.CertChain.Certificates[0].RawBytes, ca.certChain[0].der) { t.Errorf("Unexpected CertChain for %s %d wanted %s got %s", prefix, i, ca.certChain[0].der, entry.CertChain.Certificates[0].RawBytes) } } } } ================================================ FILE: pkg/tuf/context.go ================================================ // // 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. package tuf import ( "context" "time" "knative.dev/pkg/controller" ) type trustrootResyncPeriodKey struct{} // ToContext returns a context that includes a key trustrootResyncPeriod // set to the included duration func ToContext(ctx context.Context, duration time.Duration) context.Context { return context.WithValue(ctx, trustrootResyncPeriodKey{}, duration) } // FromContextOrDefaults returns a stored trustrootResyncPeriod if attached. // If not found, it returns a default duration func FromContextOrDefaults(ctx context.Context) time.Duration { x, ok := ctx.Value(trustrootResyncPeriodKey{}).(time.Duration) if ok { return x } return controller.DefaultResyncPeriod } ================================================ FILE: pkg/tuf/context_test.go ================================================ // // 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. package tuf import ( "testing" "time" "knative.dev/pkg/controller" rtesting "knative.dev/pkg/reconciler/testing" ) func TestContextDuration(t *testing.T) { ctx, _ := rtesting.SetupFakeContext(t) expected := controller.DefaultResyncPeriod actual := FromContextOrDefaults(ctx) if expected != actual { t.Fatal("Expected the context to store the value and be retrievable") } expected = time.Hour ctx = ToContext(ctx, expected) actual = FromContextOrDefaults(ctx) if expected != actual { t.Fatal("Expected the context to store the value and be retrievable") } } ================================================ FILE: pkg/tuf/repo.go ================================================ // 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. package tuf import ( "archive/tar" "bytes" "compress/gzip" "context" "errors" "fmt" "io" "io/fs" "net/http" "os" "path/filepath" "runtime" "strings" "sync" "testing/fstest" "time" "github.com/sigstore/sigstore-go/pkg/root" sigstoretuf "github.com/sigstore/sigstore-go/pkg/tuf" "github.com/sigstore/sigstore/pkg/tuf" "github.com/theupdateframework/go-tuf/v2/metadata" tufconfig "github.com/theupdateframework/go-tuf/v2/metadata/config" "github.com/theupdateframework/go-tuf/v2/metadata/fetcher" "github.com/theupdateframework/go-tuf/v2/metadata/updater" "sigs.k8s.io/release-utils/version" ) var ( // uaString is meant to resemble the User-Agent sent by browsers with requests. // See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent uaString = fmt.Sprintf("cosign/%s (%s; %s)", version.GetVersionInfo().GitVersion, runtime.GOOS, runtime.GOARCH) ) func CompressFS(fsys fs.FS, buf io.Writer, skipDirs map[string]bool) error { // tar > gzip > buf zr := gzip.NewWriter(buf) tw := tar.NewWriter(zr) walkErr := fs.WalkDir(fsys, "repository", func(file string, d fs.DirEntry, walkErr error) error { if walkErr != nil { // If we encounter an error walking, just return it and give up. return walkErr } // Skip the 'keys' and 'staged' directory if d.IsDir() && skipDirs[d.Name()] { return filepath.SkipDir } // Stat the file to get the details of it. fi, err := fs.Stat(fsys, file) if err != nil { return fmt.Errorf("fs.Stat %s: %w", file, err) } header, err := tar.FileInfoHeader(fi, file) if err != nil { return fmt.Errorf("FileInfoHeader %s: %w", file, err) } header.Name = filepath.ToSlash(file) if err := tw.WriteHeader(header); err != nil { return err } // For files, write the contents. if !d.IsDir() { data, err := fsys.Open(file) if err != nil { return fmt.Errorf("opening %s: %w", file, err) } if _, err := io.Copy(tw, data); err != nil { return fmt.Errorf("copying %s: %w", file, err) } } return nil }) if walkErr != nil { tw.Close() zr.Close() return fmt.Errorf("WalkDir: %w", walkErr) } if err := tw.Close(); err != nil { zr.Close() return fmt.Errorf("tar.NewWriter Close(): %w", err) } return zr.Close() } func Uncompress(src io.Reader, dst string) error { zr, err := gzip.NewReader(src) if err != nil { return err } tr := tar.NewReader(zr) // uncompress each element for { header, err := tr.Next() if errors.Is(err, io.EOF) { break // End of archive } if err != nil { return err } target, err := sanitizeArchivePath(dst, header.Name) // validate name against path traversal if err != nil { return err } // check the type switch header.Typeflag { // Create directories case tar.TypeDir: if _, err := os.Stat(target); err != nil { if err := os.MkdirAll(target, os.ModePerm); err != nil { return err } } // Write out files case tar.TypeReg: if header.Mode < 0 && int64(uint32(header.Mode)) != header.Mode { //nolint:gosec // disable G115 return errors.New("invalid mode value in tar header") } fileToWrite, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode)) //nolint:gosec // disable G115 if err != nil { return err } // copy over contents in chunks for security reasons // G110: Potential DoS vulnerability via decompression bomb for { _, err := io.CopyN(fileToWrite, tr, 1024) if err != nil { if errors.Is(err, io.EOF) { break } return err } } if err := fileToWrite.Close(); err != nil { return fmt.Errorf("failed to close file %s: %w", target, err) } } } return nil } // From https://github.com/securego/gosec/issues/324 func sanitizeArchivePath(d, t string) (v string, err error) { v = filepath.Join(d, t) if strings.HasPrefix(v, filepath.Clean(d)) { return v, nil } return "", fmt.Errorf("%s: %s", "content filepath is tainted", t) } // UncompressMemFS takes a TUF repository that's been compressed with CompressFS // and returns FS backed by memory. func UncompressMemFS(src io.Reader, stripPrefix string) (fs.FS, error) { testFS := fstest.MapFS{} zr, err := gzip.NewReader(src) if err != nil { return nil, err } defer zr.Close() tr := tar.NewReader(zr) // uncompress each element for { header, err := tr.Next() // EOF is unwrapped //nolint:errorlint if err == io.EOF { break // End of archive } if err != nil { return nil, err } target, err := sanitizeArchivePath("/", header.Name) // validate name against path traversal if err != nil { return nil, err } // Remove the prefix if given. Note that paths are relative to root, so // no '/' is allowed, so we always remove that. target = strings.TrimPrefix(target, stripPrefix) target = strings.TrimPrefix(target, "/") // check the type switch header.Typeflag { // Create directories case tar.TypeDir: testFS[target] = &fstest.MapFile{ Mode: os.ModeDir, ModTime: header.ModTime, } // Write out files case tar.TypeReg: data := make([]byte, header.Size) _, err := tr.Read(data) // EOF is unwrapped //nolint:errorlint if err != nil && err != io.EOF { return nil, fmt.Errorf("reading file %s : %w", header.Name, err) } if header.Mode < 0 && int64(uint32(header.Mode)) != header.Mode { //nolint:gosec // disable G115 return nil, errors.New("invalid mode value in tar header") } testFS[target] = &fstest.MapFile{ Data: data, Mode: os.FileMode(header.Mode), //nolint:gosec // disable G115 ModTime: header.ModTime, } } } return testFS, nil } // fsFetcher implements the go-tuf v2 fetcher.Fetcher interface using an fs.FS. type fsFetcher struct { fsys fs.FS baseURL string } func (f *fsFetcher) DownloadFile(urlPath string, maxLength int64, timeout time.Duration) ([]byte, error) { path := strings.TrimPrefix(urlPath, f.baseURL) path = strings.TrimPrefix(path, "/") data, err := fs.ReadFile(f.fsys, path) if err != nil { if errors.Is(err, fs.ErrNotExist) { // Return ErrDownloadHTTP with 404 so the TUF updater recognizes missing // files (e.g. during root rotation when 2.root.json doesn't exist). return nil, &metadata.ErrDownloadHTTP{StatusCode: http.StatusNotFound, URL: urlPath} } return nil, &metadata.ErrDownload{Msg: fmt.Sprintf("reading %s: %v", path, err)} } if maxLength > 0 && int64(len(data)) > maxLength { return nil, &metadata.ErrDownloadLengthMismatch{Msg: fmt.Sprintf("file %s is %d bytes, max %d", path, len(data), maxLength)} } return data, nil } // TUFClient wraps a sigstore-go TUF client for delegation-aware target // retrieval and provides lazy access to a raw go-tuf v2 updater for // legacy target enumeration via GetTopLevelTargets. type TUFClient struct { client *sigstoretuf.Client // Fields for lazy-initialized raw updater (legacy enumeration only). once sync.Once updater *updater.Updater updaterErr error metadataURL string rootJSON []byte targetsURL string fetcher fetcher.Fetcher } // GetTarget downloads a target by name, correctly traversing TUF delegations. func (c *TUFClient) GetTarget(target string) ([]byte, error) { return c.client.GetTarget(target) } // GetTopLevelTargets returns the top-level target files metadata. This does // not traverse delegations and should only be used for legacy fallback paths. // The raw updater is lazily initialized on first call to avoid a double TUF // refresh when only GetTarget is needed. func (c *TUFClient) GetTopLevelTargets() (map[string]*metadata.TargetFiles, error) { c.once.Do(func() { c.updater, c.updaterErr = newRawUpdater(c.metadataURL, c.rootJSON, c.targetsURL, c.fetcher) }) if c.updaterErr != nil { return nil, c.updaterErr } return c.updater.GetTopLevelTargets(), nil } // ClientFromSerializedMirror will construct a TUF client by // unzip/untar the repository and constructing an in-memory TUF // client for it. func ClientFromSerializedMirror(_ context.Context, repo, rootJSON []byte, targets, stripPrefix string) (*TUFClient, error) { tufFS, err := UncompressMemFS(bytes.NewReader(repo), stripPrefix) if err != nil { return nil, fmt.Errorf("failed to uncompress: %w", err) } const baseURL = "mem://repo/" f := &fsFetcher{fsys: tufFS, baseURL: baseURL} opts := sigstoretuf.DefaultOptions(). WithRoot(rootJSON). WithRepositoryBaseURL(baseURL). WithDisableLocalCache(). WithFetcher(f) client, err := sigstoretuf.New(opts) if err != nil { return nil, fmt.Errorf("failed to create TUF client: %w", err) } return &TUFClient{ client: client, metadataURL: baseURL, rootJSON: rootJSON, targetsURL: baseURL + targets + "/", fetcher: f, }, nil } // ClientFromRemote will construct a TUF client from a root and mirror. func ClientFromRemote(_ context.Context, mirror string, rootJSON []byte, targets string) (*TUFClient, error) { f := fetcher.NewDefaultFetcher() f.SetHTTPUserAgent(uaString) f.SetHTTPClient(&http.Client{Timeout: 30 * time.Second}) opts := sigstoretuf.DefaultOptions(). WithRoot(rootJSON). WithRepositoryBaseURL(mirror). WithDisableLocalCache(). WithFetcher(f) client, err := sigstoretuf.New(opts) if err != nil { return nil, fmt.Errorf("failed to create TUF client: %w", err) } return &TUFClient{ client: client, metadataURL: mirror, rootJSON: rootJSON, targetsURL: mirror + "/" + targets + "/", fetcher: f, }, nil } // newRawUpdater creates a go-tuf v2 updater for legacy target enumeration. func newRawUpdater(metadataURL string, rootJSON []byte, targetsURL string, f fetcher.Fetcher) (*updater.Updater, error) { cfg, err := tufconfig.New(metadataURL, rootJSON) if err != nil { return nil, err } cfg.Fetcher = f cfg.RemoteTargetsURL = targetsURL cfg.DisableLocalCache = true cfg.PrefixTargetsWithHash = true u, err := updater.New(cfg) if err != nil { return nil, err } if err := u.Refresh(); err != nil { return nil, err } return u, nil } var ( mu sync.RWMutex timestamp time.Time trustedRoot *root.TrustedRoot ) // GetTrustedRoot returns the trusted root for the TUF repository. func GetTrustedRoot(ctx context.Context) (*root.TrustedRoot, error) { resyncPeriodDuration := FromContextOrDefaults(ctx) now := time.Now().UTC() // check if timestamp has never been set or if the current time // is after the current timestamp value plus the included resync duration if timestamp.IsZero() || now.After(timestamp.Add(resyncPeriodDuration)) { mu.Lock() defer mu.Unlock() tufClient, err := tuf.NewFromEnv(context.Background()) if err != nil { return nil, fmt.Errorf("initializing tuf: %w", err) } // TODO: add support for custom trusted root path targetBytes, err := tufClient.GetTarget("trusted_root.json") if err != nil { return nil, fmt.Errorf("error getting targets: %w", err) } trustedRoot, err = root.NewTrustedRootFromJSON(targetBytes) if err != nil { return nil, fmt.Errorf("error creating trusted root: %w", err) } timestamp = now return trustedRoot, nil } mu.RLock() defer mu.RUnlock() return trustedRoot, nil } ================================================ FILE: pkg/tuf/repo_test.go ================================================ // 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. package tuf import ( "bytes" "context" "encoding/base64" "errors" "fmt" "net/http" "net/http/httptest" "os" "path/filepath" "testing" "testing/fstest" "time" "github.com/theupdateframework/go-tuf" "github.com/theupdateframework/go-tuf/v2/metadata" "knative.dev/pkg/logging" ) const ( fulcioRootCert = `-----BEGIN CERTIFICATE----- MIICNzCCAd2gAwIBAgITPLBoBQhl1hqFND9S+SGWbfzaRTAKBggqhkjOPQQDAjBo MQswCQYDVQQGEwJVSzESMBAGA1UECBMJV2lsdHNoaXJlMRMwEQYDVQQHEwpDaGlw cGVuaGFtMQ8wDQYDVQQKEwZSZWRIYXQxDDAKBgNVBAsTA0NUTzERMA8GA1UEAxMI dGVzdGNlcnQwHhcNMjEwMzEyMjMyNDQ5WhcNMzEwMjI4MjMyNDQ5WjBoMQswCQYD VQQGEwJVSzESMBAGA1UECBMJV2lsdHNoaXJlMRMwEQYDVQQHEwpDaGlwcGVuaGFt MQ8wDQYDVQQKEwZSZWRIYXQxDDAKBgNVBAsTA0NUTzERMA8GA1UEAxMIdGVzdGNl cnQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQRn+Alyof6xP3GQClSwgV0NFuY YEwmKP/WLWr/LwB6LUYzt5v49RlqG83KuaJSpeOj7G7MVABdpIZYWwqAiZV3o2Yw ZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQU T8Jwm6JuVb0dsiuHUROiHOOVHVkwHwYDVR0jBBgwFoAUT8Jwm6JuVb0dsiuHUROi HOOVHVkwCgYIKoZIzj0EAwIDSAAwRQIhAJkNZmP6sKA+8EebRXFkBa9DPjacBpTc OljJotvKidRhAiAuNrIazKEw2G4dw8x1z6EYk9G+7fJP5m93bjm/JfMBtA== -----END CERTIFICATE-----` ctlogPublicKey = `-----BEGIN RSA PUBLIC KEY----- MIICCgKCAgEAu1Ah4n2P8JGt92Qg86FdR8f1pou43yndggMuRCX0JB+bLn1rUFRA KQVd+xnnd4PXJLLdml8ZohCr0lhBuMxZ7zBzt0T98kblUCxBgABPNpWIkTgacyC8 MlIYY/yBSuDWAJOA5IKi4Hh9nI+Mmb/FXgbOz5a5mZx8w7pMiTMu0+Rd9cPzRkUZ DQfZsLONr6PwmyCAIL1oK80fevxKZPME0UV8bFPWnRxeVaFr5ddd/DOenV8H6SPy r4ODbSOItpl53y6Az0m3FTIUf8cSsyR7dfE4zpA3M4djjtoKDNFRsTjU2RWVQW9X MaxzznGVGhLEwkC+sYjR5NQvH5iiRvV18q+CGQqNX2+WWM3SPuty3nc86RBNR0FO gSQA0TL2OAs6bJNmfzcwZxAKYbj7/88tj6qrjLaQtFTbBm2a7+TAQfs3UTiQi00z EDYqeSj2WQvacNm1dWEAyx0QNLHiKGTn4TShGj8LUoGyjJ26Y6VPsotvCoj8jM0e aN8Pc9/AYywVI+QktjaPZa7KGH3XJHJkTIQQRcUxOtDstKpcriAefDs8jjL5ju9t 5J3qEvgzmclNJKRnla4p3maM0vk+8cC7EXMV4P1zuCwr3akaHFJo5Y0aFhKsnHqT c70LfiFo//8/QsvyjLIUtEWHTkGeuf4PpbYXr5qpJ6tWhG2MARxdeg8CAwEAAQ== -----END RSA PUBLIC KEY-----` rekorPublicKey = `-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEF6j2sTItLcs0wKoOpMzI+9lJmCzf N6mY2prOeaBRV2dnsJzC94hOxkM5pSp9nbAK1TBOI45fOOPsH2rSR++HrA== -----END PUBLIC KEY-----` // validRepository is a valid tar/gzipped repository representing an air-gap // TUF repository. validRepository = `H4sIAAAAAAAA/+xcW1MbOdPOtX+Fi9t8G0stqSWlai9m7AEMGLBjjl+9ldLRGBsMHoOBt/a/vzXmTA5kF3Cyu/NUJfYcGLW6NU8/oiXG4WSU9yej8eW7NwMhhEghZp+EkKefs+9UUMYo5VDcRxlQ/q4q3s6ke5zlEzN+R8h4NJp8777nrj/t3N8E9/Gv0Q9FHz8c5qPj122j8Ady/q34cyD0SfwFI+JddS5O/JfH/7+V6kLe7x0Hv/Cx+t9KtbrweXJ5EhY+VheKHi/8X3EqPwnu83kY5/3RcXGFfiDXF+7P0dlxuDjpj0Ne3AME8Dcif6OqS9RH4B8p27/+oUG4zG8aqy6QSAQYz7QWSLwUjrOoiPecRxfRUOK4ljRaI5mg0hBkxliQlBOUiKBuHzR77K3lwYMQVM+aK8x3B+HoaxcG4bLvPx+Y/OCzGfZG4/7k4Kgw7f9nl6sL+YEBgTd3zw4FhYXZ0X/uH3FuhndWVBdOzuyw74rGCI02YvCMRm6QRO69A4KKO23RIAAlUTqnqI1MOmWshUhVAEGVoU7o64b+KP7/Y9baApcRwKEJCjToiEIGgRCiMCJKw7k3VkcwHFgwSJxGZkNkURiU2gj7KztLOUN41ECt5AA8MCetit4QrwJ1xHDiQQftvTGcoAJUDgMNmosYpGXsS2dpxRAMs9xozUFxJ6wEQaSXTAXnfVAgWQAXA0dk2tkQg6PgpTSWOUV/YWdZDiC0C5YYDTrISALjPkiHkRLKBYKSyglGI3XOKE2IUggSWCRIePiKs6yAwJRVMjqv0IboKUdLhNPEEaBGRWUcdxSiZDJowZWKwnHJIFCJNvzCzkJEQwWxTAF3Ej2xNHoKlkcilRdoOGXBOhkEmAgyGE45807EEIMO1j90VuXGYQvj0TDck9iMKR96oO8f2v/ikfioq5ODccgPRsOCsOmDEObH5iQ/+K4hL47yDxkyMeNemOTfsePFPPZjdvSPQj4xRyffseTF6ecZS+4GjBsd5/18Eo4nnx8EajI+C5XZHbMkbCZn19mzMO96aM0sLobxiwfRzSjp94qnMSgCgNYFH5V1aLQn3jHwEINwyimhtbfRKs2VkZwbRowMaD2CAq2tQpRcIeccgaEROqDk4AEYBqYcWIFRKrTMg5DeQsDgwQFTzEnGiSj89kel+p/KHz9bAP3L8Uj/347MV54DPKP/KRXwRP8jRVbq/3ngO/r/jqfeYA5wFCbmLn3eJIzZqLvn6mE47k0OiscyFDcEW2iE+7x7rwU+VheEVNyitdZqHxUz3FCjhVUuOiBUCqeUITE4E33gGqWODIC6aJ223oroopHKKMEkiIJNhZHSGwNSUBQsSK2cx2i8Uga9lFJFobHQXYFJq4m8kQk3hj5wyl0e+EGif3GSfkT03DOggQZOVBCojTFUAmHoCJNMeQfOQaA+ghSCaAUCBaWOBURKjDEcLVrjDUXGVNBEMeWokoEIghSLxB11JFojR+2EJQIQlEBng9MCI4GS6H9tPOL/hy/iK7bxDP+DAPGU/wmBkv/nge/w/62OfwP6fzJFWHCTGD6chKOvsb9Uz5M/RqEQBBVKqEidt045RzxDSYjTkjgSKPcO0CDVnmhLNAvSBggYHYlcKqSReu+9NpYq4ilqErjVIUYqNVgTiylKUFY75yUNRChiiLQSNIVAHpO/O8sno6OHhvZ7+WQ0vp8lV6sLZ7npzdxc7y5mt3Pb6kI+MZOzmfcSN+mfh/srZ+N+cfq6qev56KMpfDwbuv7oG17U+ge8SKNHzmIgIZAoOXPKiiK5gKXMoXFIlDdWyOgJiiCYRSG9Z2BBRaRWmUi5pagCISQSCZF5ydApzxQzaLykIiqmFCGRcuKkURhl5KCt8IwIeIkXF2e9fw0/jsNgNH7JYIxWEhGsVp4QkF56rRU3qC2KwJUCxzUKNCJEjtyZaBSSgExZ8C5KEQ1DDgDMqIiKokNBDRUcpSNMWSGJlMRGBhSASBOohagVpww0KFTcvcSNnaLzL/Pin5A6L/49wCOp45QPwiPTIphCqEQRhEUlbTBCREqN9BqoBialgWIaa2JELiJTkRLqQGqC1kltJVhNkGMstBGjRAmromHKcycJJUFp4FJYSXURSCG0YToS9beUOg/y/xtVf/5S/YdyLPP/PFDWf8r6z6/grLL+U9Z/yvpPWf8p6z9l/afE/PBA/79R9ecv1X8I8FL/zwNl/aes/5T1n38vHvD/zWv4+m2QP73+myOKcv33PPBl/Gub5mI5GB/G+QdSe42awDfifhd/EI/HAgEhGL6rXszDAbfxn0dbvyAoquqJmRz8/pWB8LPrQR/uS1qVn+2nfyrmEfbn9L/k+Jj/GaFMlvp/HvitQJotNder9azTbS4260k3m52ttJrNdPOwnorVpJH0snrxr5WMlur106VPLa7TpFVvJeSifpWspL317TRpdZOj9YNWyncb3SZUWo3sYqOR8NZh+6I1HO02ui14cm7auMrWW0m+lNCtLLloZXZp+2D/MN1vpa2lSnp53VLSy+5aTabZckKaSVo/bu2KUWPtNAm1qzwTw4uTE59f5aupzs/rtbWD3a1KurYxUF0Ug/WG/nS5u6RaCX3/6XQHmg73OsdHYgyH789r9U4fh0u7OVlq4GHrKrloJbywyFca0yytTdtZMm0uTRtJLPq5/KmVLTWSnV7aYZNVgRs7q7s4Ojqkm7VBtjM4H/Q72Uk3WU17vdPKweBwY7PdbiS99ZWkkS4l/SzRa/2s+543PrlNt7m2ic3909GAk7o8Z5uXI7LotwZ723XeGfu9eqXZrnfiynS4eGinbLnVXls/7++RenLQU0tJ3jrKTxe3asnKxrCpbG/6+++VWfCy9caXAX0u2J+69VSZu2Cnrx/sbrbWSga3wa7vQTbd6SbdtOduPdVMC7ddf2+l6XS9niSdLd1/v7VxtrzaWcmHp4PQ3Gyp5fNxbeP4YvR+vGMustE5rVyk2fvzw91hLYbF+lGfqV7SbIraVu80294fLortNPVhmO2ntM8vczsdkea03Ug2ZjFtq7SSRJUV/Ux67WljutfY7pBu0l6upcnWNCkGwlXir2/m2WKvveXlp7NwOOwP35+ujHS3VhHp4smaaA46q1vTem+vuTrab14dkmL0NDrTZNpJmj2zOBGddhzsLQ1h0r7c2K3pbkxdXygyrvSOW7WsvhrC+DS9XG3Wm+l5urHEruJOKk8Xt+qj/LCXD4+E6V7srO3ZoffrZnXJjg+vtP5O4L/9/j+n/15jZc2z+o/jU/0HXJb6bx6giN/Ufz97VdWH22Vhpfp7M8wj7M/oPwIIX+g/Tkr9Nw88kASbW+las15dzfZuFMHiYJpN95Zvklg9ad8ltEbSdo12L8lUfW9d1Ae1nph09i/Olt1Zd6iicid8+7jC6PCqv6lHK7BpV7yyhzvbpsE3G921AW5uu81Jf3mShWy9trJOu5PT9mCrl7eG9WgeqZinZv1sj/2z8Fz+f43FjM/nf/k0/zPJy/w/D1CU38z/P3sh64e7pbjlS/9WmEfY/3T+Bylpuf9jLnhh/vfLV2M7PJpGftDK2PuNiVyDVC0Oup52Kp2Y58fDgz58uty6bO+pjeOTddw8XMSJ3PXmcv1iRe7ube+Etf2ktsRXe4K26/LSrtBemf/nhS/f/9dfAv7M+/+V/V8Cebn/dy4o93+V+7/K/V/l/q9y/9e/fv/X3XrpOe//plSwL/7+h6Rl/p8Hvpf/79bPv/UC0Ecrj79Cu0h/RANAoCQSTRmitSFCIJIwQMkjMdKiIJ4rpFwwKr0UTNFoXVDceOlJ8ER5KpkGSwn10jJ0hmtPDZXRW2+shwhFd0Bawp3QIhrFuC74GhljUr3aAtAX70l4xIpKcgyMExaVA8PQWoLKU+RUOWKIi5I5cMEEL50R3AvDKNOUMWBguLPaUO44KzhVWMK1DdHGSJUQgRLhvVQiBssEOCNVcKCNpDwqpqnkQAj/W7JiiRIlSvzz8b8AAAD//1nncb4AXAAA` // IMPORTANT: The next expiration is on '2026-07-18T08:24:13Z' // Steps to generate: // 1. cgit clone github.com/sigstore/scaffolding // 2. run ./hack/setup-kind.sh // 3. export KO_DOCKER_REPO=registry.local:5001/sigstore // 4. run ./hack/setup-scaffolding.sh // 5. get the secrets from the kind cluster // kubectl get secrets -o yaml -n tuf-system tuf-root rootJSON = `ewogInNpZ25lZCI6IHsKICAiX3R5cGUiOiAicm9vdCIsCiAgInNwZWNfdmVyc2lvbiI6ICIxLjAiLAogICJ2ZXJzaW9uIjogMSwKICAiZXhwaXJlcyI6ICIyMDI2LTA3LTE4VDA4OjI0OjEzWiIsCiAgImtleXMiOiB7CiAgICIwZjA1MmFkMzk5NTYwZDc1YzQzZjgwZGQ0NGZjZjZhMTBjNDk3MWZiYTczNTE3YTA2M2FhYjI3MTQwNjc2NjI4IjogewogICAgImtleXR5cGUiOiAiZWQyNTUxOSIsCiAgICAic2NoZW1lIjogImVkMjU1MTkiLAogICAgImtleWlkX2hhc2hfYWxnb3JpdGhtcyI6IFsKICAgICAic2hhMjU2IiwKICAgICAic2hhNTEyIgogICAgXSwKICAgICJrZXl2YWwiOiB7CiAgICAgInB1YmxpYyI6ICIwMWZiZjZlZDMxZjRhNjBmNGRkYzIwNjg0YzliNmE2MjIxMGY3Y2M4MWJmMzdjOGFiYjJmMThlMjUxOGExYzU5IgogICAgfQogICB9LAogICAiNDdmMjJjNmFlODI5MjlmNjU3ZTU2MmVmNWE1ZjdhNDRkYWI5ZjJhNDIzZWE2MGM5NjNiZWYzZjVhNjc5YTViOCI6IHsKICAgICJrZXl0eXBlIjogImVkMjU1MTkiLAogICAgInNjaGVtZSI6ICJlZDI1NTE5IiwKICAgICJrZXlpZF9oYXNoX2FsZ29yaXRobXMiOiBbCiAgICAgInNoYTI1NiIsCiAgICAgInNoYTUxMiIKICAgIF0sCiAgICAia2V5dmFsIjogewogICAgICJwdWJsaWMiOiAiOGNhMDRmOTIxYjc0MjI0ZTNjN2I4ZmRhMGQ4ZTFjMGE0MGQyOWU5ZGRhYTQwNjgyNjhjNmUxZTk0NWZlN2IzMyIKICAgIH0KICAgfSwKICAgIjk4MzYyYTNiNGE5OTQyODRjNWI3MjUwN2Q3MzhlY2RkZTgyNzNlMmNmZTQ2NjM5Y2JlZmVjMTJkNzdhYjNjODEiOiB7CiAgICAia2V5dHlwZSI6ICJlZDI1NTE5IiwKICAgICJzY2hlbWUiOiAiZWQyNTUxOSIsCiAgICAia2V5aWRfaGFzaF9hbGdvcml0aG1zIjogWwogICAgICJzaGEyNTYiLAogICAgICJzaGE1MTIiCiAgICBdLAogICAgImtleXZhbCI6IHsKICAgICAicHVibGljIjogImI0MjI1OWNlYjBhOTI5ZTdmMGUzNGRlN2M2ZjEwMTQ1NjI4NzhjNTMxZjFjY2E4OTAwODg2MjcyM2YwNjA0ZTMiCiAgICB9CiAgIH0sCiAgICJiNTJlMzhiODdmY2Q4NmJlZmQxNDZiMDVjOTBjMDIxYThmOGFjNGMxMmY3MzdlOTU0ODhmNWM0NzMyZTE3NmJlIjogewogICAgImtleXR5cGUiOiAiZWQyNTUxOSIsCiAgICAic2NoZW1lIjogImVkMjU1MTkiLAogICAgImtleWlkX2hhc2hfYWxnb3JpdGhtcyI6IFsKICAgICAic2hhMjU2IiwKICAgICAic2hhNTEyIgogICAgXSwKICAgICJrZXl2YWwiOiB7CiAgICAgInB1YmxpYyI6ICI2NjZhMTUwYjM4MjRjNzZkMGIxZmQxMmI0ZjA3OGQ1NmE0MTNlYmM3ZTUyYWYyN2VhNDE0M2RjNWZlZmU5ZWJkIgogICAgfQogICB9CiAgfSwKICAicm9sZXMiOiB7CiAgICJyb290IjogewogICAgImtleWlkcyI6IFsKICAgICAiOTgzNjJhM2I0YTk5NDI4NGM1YjcyNTA3ZDczOGVjZGRlODI3M2UyY2ZlNDY2MzljYmVmZWMxMmQ3N2FiM2M4MSIKICAgIF0sCiAgICAidGhyZXNob2xkIjogMQogICB9LAogICAic25hcHNob3QiOiB7CiAgICAia2V5aWRzIjogWwogICAgICJiNTJlMzhiODdmY2Q4NmJlZmQxNDZiMDVjOTBjMDIxYThmOGFjNGMxMmY3MzdlOTU0ODhmNWM0NzMyZTE3NmJlIgogICAgXSwKICAgICJ0aHJlc2hvbGQiOiAxCiAgIH0sCiAgICJ0YXJnZXRzIjogewogICAgImtleWlkcyI6IFsKICAgICAiNDdmMjJjNmFlODI5MjlmNjU3ZTU2MmVmNWE1ZjdhNDRkYWI5ZjJhNDIzZWE2MGM5NjNiZWYzZjVhNjc5YTViOCIKICAgIF0sCiAgICAidGhyZXNob2xkIjogMQogICB9LAogICAidGltZXN0YW1wIjogewogICAgImtleWlkcyI6IFsKICAgICAiMGYwNTJhZDM5OTU2MGQ3NWM0M2Y4MGRkNDRmY2Y2YTEwYzQ5NzFmYmE3MzUxN2EwNjNhYWIyNzE0MDY3NjYyOCIKICAgIF0sCiAgICAidGhyZXNob2xkIjogMQogICB9CiAgfSwKICAiY29uc2lzdGVudF9zbmFwc2hvdCI6IHRydWUKIH0sCiAic2lnbmF0dXJlcyI6IFsKICB7CiAgICJrZXlpZCI6ICI5ODM2MmEzYjRhOTk0Mjg0YzViNzI1MDdkNzM4ZWNkZGU4MjczZTJjZmU0NjYzOWNiZWZlYzEyZDc3YWIzYzgxIiwKICAgInNpZyI6ICIzMjIyYzY2YmNlZGY4YmM2YTlkMGRjMzJkMmZlNWM4Yzg1OTlkYmZiODk0OGE3NDRhMzBhN2U2YmQ2MjgyOTliODY2NzQ4NjQ0NDYyMzZhNTllNjc0MmQyMjM2ZTM4YzJiNTZmNzg2YjNkMjU3ZGIyZTZlZDJjMjM4M2M3MzQwNSIKICB9CiBdCn0=` ) func TestCompressUncompressFS(t *testing.T) { files := map[string][]byte{ "fulcio_v1.crt.pem": []byte(fulcioRootCert), "ctfe.pub": []byte(ctlogPublicKey), "rekor.pub": []byte(rekorPublicKey), } repo, dir, err := createRepo(context.Background(), files) if err != nil { t.Fatalf("Failed to CreateRepo: %s", err) } defer os.RemoveAll(dir) var buf bytes.Buffer fsys := os.DirFS(dir) if err = CompressFS(fsys, &buf, map[string]bool{"keys": true, "staged": true}); err != nil { t.Fatalf("Failed to compress: %v", err) } os.WriteFile("/tmp/newcompressed", buf.Bytes(), os.ModePerm) dstDir := t.TempDir() if err = Uncompress(&buf, dstDir); err != nil { t.Fatalf("Failed to uncompress: %v", err) } // Then check that files have been uncompressed there. meta, err := repo.GetMeta() if err != nil { t.Errorf("Failed to GetMeta: %s", err) } root := meta["root.json"] // This should have roundtripped to the new directory. rtRoot, err := os.ReadFile(filepath.Join(dstDir, "repository", "root.json")) if err != nil { t.Errorf("Failed to read the roundtripped root %v", err) } if !bytes.Equal(root, rtRoot) { t.Errorf("Roundtripped root differs:\n%s\n%s", string(root), string(rtRoot)) } // As well as, say rekor.pub under targets dir rtRekor, err := os.ReadFile(filepath.Join(dstDir, "repository", "targets", "rekor.pub")) if err != nil { t.Errorf("Failed to read the roundtripped rekor %v", err) } if !bytes.Equal(files["rekor.pub"], rtRekor) { t.Errorf("Roundtripped rekor differs:\n%s\n%s", rekorPublicKey, string(rtRekor)) } } func createRepo(ctx context.Context, files map[string][]byte) (tuf.LocalStore, string, error) { // TODO: Make this an in-memory fileystem. // tmpDir := os.TempDir() // dir := tmpDir + "tuf" dir := "/tmp/tuf" err := os.Mkdir(dir, os.ModePerm) if err != nil { return nil, "", fmt.Errorf("failed to create tmp TUF dir: %w", err) } dir += "/" logging.FromContext(ctx).Infof("Creating the FS in %q", dir) local := tuf.FileSystemStore(dir, nil) // Create and commit a new TUF repo with the targets to the store. logging.FromContext(ctx).Infof("Creating new repo in %q", dir) r, err := tuf.NewRepoIndent(local, "", " ") if err != nil { return nil, "", fmt.Errorf("failed to NewRepoIndent: %w", err) } // Added by vaikas if err := r.Init(false); err != nil { return nil, "", fmt.Errorf("failed to Init repo: %w", err) } // Make all metadata files expire in 6 months. expires := time.Now().AddDate(0, 6, 0) for _, role := range []string{"root", "targets", "snapshot", "timestamp"} { _, err := r.GenKeyWithExpires(role, expires) if err != nil { return nil, "", fmt.Errorf("failed to GenKeyWithExpires: %w", err) } } targets := make([]string, 0, len(files)) for k, v := range files { logging.FromContext(ctx).Infof("Adding %s file", k) if err := writeStagedTarget(dir, k, v); err != nil { return nil, "", fmt.Errorf("failed to write staged target %s: %w", k, err) } targets = append(targets, k) } err = r.AddTargetsWithExpires(targets, nil, expires) if err != nil { return nil, "", fmt.Errorf("failed to add AddTargetsWithExpires: %w", err) } // Snapshot, Timestamp, and Publish the repository. if err := r.SnapshotWithExpires(expires); err != nil { return nil, "", fmt.Errorf("failed to add SnapShotWithExpires: %w", err) } if err := r.TimestampWithExpires(expires); err != nil { return nil, "", fmt.Errorf("failed to add TimestampWithExpires: %w", err) } if err := r.Commit(); err != nil { return nil, "", fmt.Errorf("failed to Commit: %w", err) } return local, dir, nil } func writeStagedTarget(dir, path string, data []byte) error { path = filepath.Join(dir, "staged", "targets", path) if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { return err } return os.WriteFile(path, data, 0644) } func TestFsFetcherNotFound(t *testing.T) { testFS := fstest.MapFS{ "existing.json": &fstest.MapFile{Data: []byte(`{"hello":"world"}`)}, } f := &fsFetcher{fsys: testFS, baseURL: "mem://test/"} // Existing file should succeed data, err := f.DownloadFile("mem://test/existing.json", 0, 0) if err != nil { t.Fatalf("unexpected error for existing file: %v", err) } if string(data) != `{"hello":"world"}` { t.Errorf("unexpected data: %s", data) } // Missing file should return ErrDownloadHTTP with 404 _, err = f.DownloadFile("mem://test/missing.json", 0, 0) if err == nil { t.Fatal("expected error for missing file") } var httpErr *metadata.ErrDownloadHTTP if !errors.As(err, &httpErr) || httpErr.StatusCode != 404 { t.Errorf("expected ErrDownloadHTTP{404}, got: %v", err) } } func TestFsFetcherMaxLength(t *testing.T) { testFS := fstest.MapFS{ "big.json": &fstest.MapFile{Data: make([]byte, 100)}, } f := &fsFetcher{fsys: testFS, baseURL: "mem://test/"} // Should succeed when maxLength is 0 (unlimited) _, err := f.DownloadFile("mem://test/big.json", 0, 0) if err != nil { t.Fatalf("unexpected error: %v", err) } // Should fail when file exceeds maxLength _, err = f.DownloadFile("mem://test/big.json", 50, 0) if err == nil { t.Fatal("expected error for oversized file") } var lenErr *metadata.ErrDownloadLengthMismatch if !errors.As(err, &lenErr) { t.Errorf("expected ErrDownloadLengthMismatch, got: %v", err) } } func TestDownloadTargetFromSerializedMirror(t *testing.T) { repo, err := base64.StdEncoding.DecodeString(validRepository) if err != nil { t.Fatalf("failed to decode validrepository: %v", err) } root, err := base64.StdEncoding.DecodeString(rootJSON) if err != nil { t.Fatalf("failed to decode rootJSON: %v", err) } tufClient, err := ClientFromSerializedMirror(context.Background(), repo, root, "targets", "/repository/") if err != nil { t.Fatalf("Failed to create client: %v", err) } // Download each target via GetTarget and verify it has content targets, err := tufClient.GetTopLevelTargets() if err != nil { t.Fatalf("GetTopLevelTargets error: %v", err) } for name := range targets { data, err := tufClient.GetTarget(name) if err != nil { t.Errorf("GetTarget(%s) error: %v", name, err) continue } if len(data) == 0 { t.Errorf("GetTarget(%s) returned empty data", name) } } } func TestClientFromSerializedMirror(t *testing.T) { repo, err := base64.StdEncoding.DecodeString(validRepository) if err != nil { t.Fatalf("failed to decode validrepository: %v", err) } root, err := base64.StdEncoding.DecodeString(rootJSON) if err != nil { t.Fatalf("failed to decode rootJSON: %v", err) } tufClient, err := ClientFromSerializedMirror(context.Background(), repo, root, "targets", "/repository/") if err != nil { t.Fatalf("Failed to unserialize repo: %v", err) } targets, err := tufClient.GetTopLevelTargets() if err != nil { t.Fatalf("GetTopLevelTargets error: %v", err) } if len(targets) == 0 { t.Errorf("Got no targets from the TUF client") } } func TestClientFromRemoteMirror(t *testing.T) { files := map[string][]byte{ "fulcio_v1.crt.pem": []byte(fulcioRootCert), "ctfe.pub": []byte(ctlogPublicKey), "rekor.pub": []byte(rekorPublicKey), } local, dir, err := createRepo(context.Background(), files) if err != nil { t.Fatalf("Failed to CreateRepo: %s", err) } defer os.RemoveAll(dir) meta, err := local.GetMeta() if err != nil { t.Fatalf("getting meta: %v", err) } rootJSON, ok := meta["root.json"] if !ok { t.Fatalf("Getting root: %v", err) } serveDir := filepath.Join(dir, "repository") t.Logf("tuf repository was created in: %s serving tuf root at %s", dir, serveDir) fs := http.FileServer(http.Dir(serveDir)) http.Handle("/", fs) ts := httptest.NewServer(fs) defer ts.Close() tufClient, err := ClientFromRemote(context.Background(), ts.URL, rootJSON, "targets") if err != nil { t.Fatalf("Failed to get client from remote: %v", err) } targets, err := tufClient.GetTopLevelTargets() if err != nil { t.Fatalf("GetTopLevelTargets error: %v", err) } if len(targets) == 0 { t.Errorf("Got no targets from the TUF client") } } ================================================ FILE: pkg/webhook/cache.go ================================================ // // 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. package webhook import ( "context" ) type cacheKey struct{} // CacheResult wraps PolicyResult and errors that are suitable for caching // purposes. By doing this we can make choices that control things like, should // errors be cached, and if so, for how long that's independent of the // successful validations. type CacheResult struct { PolicyResult *PolicyResult Errors []error } // FromContext extracts a cache from the provided context. If one has not been // set, return the NoCache to fulfill the interface but it provides no caching. func FromContext(ctx context.Context) ResultCache { x, ok := ctx.Value(cacheKey{}).(ResultCache) if ok { return x } return &NoCache{} } func ToContext(ctx context.Context, cache ResultCache) context.Context { return context.WithValue(ctx, cacheKey{}, cache) } type ResultCache interface { // Set caches a PolicyResult for a given CIP evaluated for a given image at // a particular point in time. image, uid & resourceVersion will give a // unique point in time, so we can make sure we're not caching things that // are out of date. Set(ctx context.Context, image, name, uid, resourceVersion string, cacheResult *CacheResult) // Get returns a cached result for a given image or nil if there are none. Get(ctx context.Context, image, uid, resourceVersion string) *CacheResult } ================================================ FILE: pkg/webhook/clusterimagepolicy/clusterimagepolicy_types.go ================================================ // 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. package clusterimagepolicy import ( "context" "crypto" "encoding/json" "fmt" "github.com/google/go-containerregistry/pkg/authn/k8schain" "github.com/google/go-containerregistry/pkg/authn/kubernetes" "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1/remote" ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" signaturealgo "github.com/sigstore/policy-controller/pkg/apis/signaturealgo" "github.com/sigstore/policy-controller/pkg/webhook/registryauth" "github.com/sigstore/sigstore/pkg/cryptoutils" "k8s.io/apimachinery/pkg/types" "knative.dev/pkg/apis" kubeclient "knative.dev/pkg/client/injection/kube/client" "knative.dev/pkg/logging" "knative.dev/pkg/ptr" ) // ClusterImagePolicy defines the images that go through verification // and the authorities used for verification. // This is the internal representation of the external v1alpha1.ClusterImagePolicy. // KeyRef does not store secretRefs in internal representation. // KeyRef does store parsed publicKeys from Data in internal representation. type ClusterImagePolicy struct { // UID of the CIP so we can tell if they've been deleted/recreated UID types.UID `json:"uid,inline"` // ResourceVersion can be used to know if the CIP has been modified ResourceVersion string `json:"resourceVersion"` Images []v1alpha1.ImagePattern `json:"images"` Authorities []Authority `json:"authorities"` // Policy is an optional policy used to evaluate the results of valid // Authorities. Will not get evaluated unless at least one Authority // succeeds. Policy *AttestationPolicy `json:"policy,omitempty"` // Mode controls whether a failing policy will be rejected (not admitted), // or if errors are converted to Warnings. // enforce - Reject (default) // warn - allow but warn // +optional Mode string `json:"mode,omitempty"` // Match allows selecting resources based on their properties. Match []v1alpha1.MatchResource `json:"match,omitempty"` } type Authority struct { // Name is the name for this authority. Used by the CIP Policy // validator to be able to reference matching signature or attestation // verifications. Name string `json:"name"` // +optional Key *KeyRef `json:"key,omitempty"` // +optional Keyless *KeylessRef `json:"keyless,omitempty"` // +optional Static *StaticRef `json:"static,omitempty"` // +optional Sources []v1alpha1.Source `json:"source,omitempty"` // +optional CTLog *v1alpha1.TLog `json:"ctlog,omitempty"` // RemoteOpts are not marshalled because they are an unsupported type // RemoteOpts will be populated by the Authority UnmarshalJSON override // +optional RemoteOpts []ociremote.Option `json:"-"` // +optional Attestations []AttestationPolicy `json:"attestations,omitempty"` // +optional RFC3161Timestamp *RFC3161Timestamp `json:"rfc3161timestamp,omitempty"` // +optional SignatureFormat string `json:"signatureFormat,omitempty"` } // This references a public verification key stored in // a secret in the cosign-system namespace. type KeyRef struct { // Data contains the inline public key // +optional Data string `json:"data,omitempty"` // HashAlgorithm always defaults to sha256 if the algorithm hasn't been explicitly set // +optional HashAlgorithm string `json:"hashAlgorithm,omitempty"` // HashAlgorithmCode sets the crypto.Hash code based on the value of HashAlgorithm. // HashAlgorithmCode is not marshalled, but we use the calculated crypto.Hash in the validations // +optional HashAlgorithmCode crypto.Hash `json:"-"` // PublicKeys are not marshalled because JSON unmarshalling // errors for *big.Int // +optional PublicKeys []crypto.PublicKey `json:"-"` } type KeylessRef struct { // +optional URL *apis.URL `json:"url,omitempty"` // +optional Identities []v1alpha1.Identity `json:"identities,omitempty"` // +optional CACert *KeyRef `json:"ca-cert,omitempty"` // Use the Certificate Chain from the referred TrustRoot.CertificateAuthorities and TrustRoot.CTLog // +optional TrustRootRef string `json:"trustRootRef,omitempty"` // InsecureIgnoreSCT omits verifying if a certificate contains an embedded SCT // +optional InsecureIgnoreSCT *bool `json:"insecureIgnoreSCT,omitempty"` } type StaticRef struct { Action string `json:"action"` Message string `json:"message,omitempty"` } type AttestationPolicy struct { // Name of the Attestation Name string `json:"name"` // PredicateType to attest, one of the accepted in verify-attestation PredicateType string `json:"predicateType"` // Type specifies how to evaluate policy, only rego/cue are understood. Type string `json:"type,omitempty"` // Data is the inlined version of the Policy used to evaluate the // Attestation. Data string `json:"data,omitempty"` // FetchConfigFile controls whether ConfigFile will be fetched and made // available for CIP level policy evaluation. Note that this only gets // evaluated (and hence fetched) iff at least one authority matches. // The ConfigFile will then be available in this format: // https://github.com/opencontainers/image-spec/blob/main/config.md FetchConfigFile *bool `json:"fetchConfigFile,omitempty"` // IncludeSpec controls whether resource `Spec` will be included and // made available for CIP level policy evaluation. Note that this only gets // evaluated iff at least one authority matches. IncludeSpec *bool `json:"includeSpec,omitempty"` // IncludeObjectMeta controls whether the ObjectMeta will be included and // made available for CIP level policy evalutation. Note that this only gets // evaluated iff at least one authority matches. // +optional IncludeObjectMeta *bool `json:"includeObjectMeta,omitempty"` // IncludeTypeMeta controls whether the TypeMeta will be included and // made available for CIP level policy evalutation. Note that this only gets // evaluated iff at least one authority matches. // +optional IncludeTypeMeta *bool `json:"includeTypeMeta,omitempty"` } // RFC3161Timestamp specifies the URL to a RFC3161 time-stamping server that holds // the time-stamped verification for the signature type RFC3161Timestamp struct { // Use the Certificate Chain from the referred TrustRoot.TimeStampAuthorities // +optional TrustRootRef string `json:"trustRootRef,omitempty"` } // UnmarshalJSON populates the PublicKeys using Data because // JSON unmashalling errors for *big.Int func (k *KeyRef) UnmarshalJSON(data []byte) error { var publicKeys []crypto.PublicKey var err error ret := make(map[string]string) if err = json.Unmarshal(data, &ret); err != nil { return err } k.Data = ret["data"] k.HashAlgorithmCode = crypto.SHA256 k.HashAlgorithm = signaturealgo.DefaultSignatureAlgorithm if ret["hashAlgorithm"] != "" { k.HashAlgorithm = ret["hashAlgorithm"] k.HashAlgorithmCode, err = signaturealgo.HashAlgorithm(ret["hashAlgorithm"]) if err != nil { return err } } if ret["data"] != "" { publicKey, err := cryptoutils.UnmarshalPEMToPublicKey([]byte(ret["data"])) if err != nil { return fmt.Errorf("failed to unmarshal PEM public key %w", err) } publicKeys = append(publicKeys, publicKey) } k.PublicKeys = publicKeys return nil } // UnmarshalJSON populates the authority with the remoteOpts // from authority sources func (a *Authority) UnmarshalJSON(data []byte) error { // Create a new type to avoid recursion type RawAuthority Authority var rawAuthority RawAuthority err := json.Unmarshal(data, &rawAuthority) if err != nil { return err } // Determine additional RemoteOpts if len(rawAuthority.Sources) > 0 { for _, source := range rawAuthority.Sources { if source.OCI != "" { if targetRepoOverride, err := name.NewRepository(source.OCI); err != nil { return fmt.Errorf("failed to determine source: %w", err) } else if (targetRepoOverride != name.Repository{}) { rawAuthority.RemoteOpts = append(rawAuthority.RemoteOpts, ociremote.WithTargetRepository(targetRepoOverride)) } } if source.TagPrefix != nil && *source.TagPrefix != "" { rawAuthority.RemoteOpts = append(rawAuthority.RemoteOpts, ociremote.WithPrefix(*source.TagPrefix)) } } } // Set the new type instance to casted original *a = Authority(rawAuthority) return nil } // SourceSignaturePullSecretsOpts creates the signaturePullSecrets remoteOpts // This is not stored in the Authority under RemoteOpts as the namespace can be different func (a *Authority) SourceSignaturePullSecretsOpts(ctx context.Context, namespace string) ([]ociremote.Option, error) { var ret []ociremote.Option for _, source := range a.Sources { if len(source.SignaturePullSecrets) > 0 { signaturePullSecrets := make([]string, 0, len(source.SignaturePullSecrets)) for _, s := range source.SignaturePullSecrets { signaturePullSecrets = append(signaturePullSecrets, s.Name) } // Use NoServiceAccount when setting a signaturePullSecrets to avoid unnecessary API calls. opt := k8schain.Options{ Namespace: namespace, ServiceAccountName: kubernetes.NoServiceAccount, ImagePullSecrets: signaturePullSecrets, } kc, err := registryauth.NewK8sKeychain(ctx, kubeclient.Get(ctx), opt) if err != nil { logging.FromContext(ctx).Errorf("failed creating keychain: %+v", err) return nil, err } ret = append(ret, ociremote.WithRemoteOptions( remote.WithContext(ctx), remote.WithAuthFromKeychain(kc), )) } } return ret, nil } func ConvertClusterImagePolicyV1alpha1ToWebhook(in *v1alpha1.ClusterImagePolicy) *ClusterImagePolicy { copyIn := in.DeepCopy() outAuthorities := make([]Authority, 0) for _, authority := range copyIn.Spec.Authorities { outAuthority := convertAuthorityV1Alpha1ToWebhook(authority) outAuthorities = append(outAuthorities, *outAuthority) } // If there's a ClusterImagePolicy level AttestationPolicy, convert it here. var cipAttestationPolicy *AttestationPolicy if in.Spec.Policy != nil { cipAttestationPolicy = &AttestationPolicy{ Type: in.Spec.Policy.Type, Data: in.Spec.Policy.Data, } if in.Spec.Policy.FetchConfigFile != nil { cipAttestationPolicy.FetchConfigFile = ptr.Bool(*in.Spec.Policy.FetchConfigFile) } if in.Spec.Policy.IncludeSpec != nil { cipAttestationPolicy.IncludeSpec = ptr.Bool(*in.Spec.Policy.IncludeSpec) } if in.Spec.Policy.IncludeObjectMeta != nil { cipAttestationPolicy.IncludeObjectMeta = ptr.Bool(*in.Spec.Policy.IncludeObjectMeta) } if in.Spec.Policy.IncludeTypeMeta != nil { cipAttestationPolicy.IncludeTypeMeta = ptr.Bool(*in.Spec.Policy.IncludeTypeMeta) } } return &ClusterImagePolicy{ UID: copyIn.UID, ResourceVersion: copyIn.ResourceVersion, Images: copyIn.Spec.Images, Authorities: outAuthorities, Policy: cipAttestationPolicy, Mode: in.Spec.Mode, Match: in.Spec.Match, } } func convertAuthorityV1Alpha1ToWebhook(in v1alpha1.Authority) *Authority { keyRef := convertKeyRefV1Alpha1ToWebhook(in.Key) keylessRef := convertKeylessRefV1Alpha1ToWebhook(in.Keyless) staticRef := convertStaticRefV1Alpha1ToWebhook(in.Static) attestations := convertAttestationsV1Alpha1ToWebhook(in.Attestations) rfc3161Timestamp := convertRFC3161TimestampV1Alpha1ToWebhook(in.RFC3161Timestamp) return &Authority{ Name: in.Name, Key: keyRef, Keyless: keylessRef, Static: staticRef, Sources: in.Sources, CTLog: in.CTLog, RFC3161Timestamp: rfc3161Timestamp, Attestations: attestations, SignatureFormat: in.SignatureFormat, } } func convertRFC3161TimestampV1Alpha1ToWebhook(in *v1alpha1.RFC3161Timestamp) *RFC3161Timestamp { if in == nil { return nil } return &RFC3161Timestamp{ TrustRootRef: in.TrustRootRef, } } func convertAttestationsV1Alpha1ToWebhook(in []v1alpha1.Attestation) []AttestationPolicy { ret := []AttestationPolicy{} for _, inAtt := range in { outAtt := AttestationPolicy{ Name: inAtt.Name, PredicateType: inAtt.PredicateType, } if inAtt.Policy != nil { outAtt.Type = inAtt.Policy.Type outAtt.Data = inAtt.Policy.Data if inAtt.Policy.FetchConfigFile != nil { outAtt.FetchConfigFile = ptr.Bool(*inAtt.Policy.FetchConfigFile) } if inAtt.Policy.IncludeSpec != nil { outAtt.IncludeSpec = ptr.Bool(*inAtt.Policy.IncludeSpec) } if inAtt.Policy.IncludeObjectMeta != nil { outAtt.IncludeObjectMeta = ptr.Bool(*inAtt.Policy.IncludeObjectMeta) } if inAtt.Policy.IncludeTypeMeta != nil { outAtt.IncludeTypeMeta = ptr.Bool(*inAtt.Policy.IncludeTypeMeta) } } ret = append(ret, outAtt) } return ret } func convertKeyRefV1Alpha1ToWebhook(in *v1alpha1.KeyRef) *KeyRef { if in == nil { return nil } // Convert the hash algorithm name to the code and reuse it everywhere else algorithmCode := crypto.SHA256 algorithm := signaturealgo.DefaultSignatureAlgorithm if in.HashAlgorithm != "" { algorithm = in.HashAlgorithm // Ignore the error. It was already validated by the validation webhook algorithmCode, _ = signaturealgo.HashAlgorithm(in.HashAlgorithm) // nolint: staticcheck } return &KeyRef{ Data: in.Data, HashAlgorithm: algorithm, HashAlgorithmCode: algorithmCode, } } func convertKeylessRefV1Alpha1ToWebhook(in *v1alpha1.KeylessRef) *KeylessRef { if in == nil { return nil } CACertRef := convertKeyRefV1Alpha1ToWebhook(in.CACert) return &KeylessRef{ URL: in.URL, Identities: in.Identities, CACert: CACertRef, TrustRootRef: in.TrustRootRef, InsecureIgnoreSCT: in.InsecureIgnoreSCT, } } func convertStaticRefV1Alpha1ToWebhook(in *v1alpha1.StaticRef) *StaticRef { if in == nil { return nil } return &StaticRef{ Action: in.Action, Message: in.Message, } } ================================================ FILE: pkg/webhook/nocache.go ================================================ // // 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. package webhook import "context" // NoCache is pretty much what it says, it caches nothing. Just meant to // implement the interface that we can test with as well as if there is no // caching wanted, we can do that by injecting this. type NoCache struct { } func (nc *NoCache) Get(ctx context.Context, image, uid, resourceVersion string) *CacheResult { //nolint: revive return nil } func (nc *NoCache) Set(ctx context.Context, image, name, uid, resourceVersion string, cacheResult *CacheResult) { //nolint: revive } ================================================ FILE: pkg/webhook/registryauth/azure/acrhelper.go ================================================ // // 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. package azure import ( "context" "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" "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "github.com/docker/docker-credential-helpers/credentials" ) type ACRHelper struct{} func NewACRHelper() credentials.Helper { return &ACRHelper{} } func (a ACRHelper) Add(_ *credentials.Credentials) error { return fmt.Errorf("add is unimplemented") } func (a ACRHelper) Delete(_ string) error { return fmt.Errorf("delete is unimplemented") } 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) } // We need to set the desired token policy to https://management.azure.com // to get a token that can be used to authenticate to the Azure Container Registry. opts := policy.TokenRequestOptions{ Scopes: []string{"https://management.azure.com/.default"}, } accessToken, err := azCred.GetToken(context.Background(), opts) if err != nil { return "", "", fmt.Errorf("failed to get token: %w", err) } registryWithScheme, err := url.Parse(fmt.Sprintf("https://%s", registryURL)) if err != nil { return "", "", fmt.Errorf("failed to parse registry URL: %w", err) } tenantID := os.Getenv("AZURE_TENANT_ID") if tenantID == "" { return "", "", fmt.Errorf("AZURE_TENANT_ID environment variable not found") } repoClient := containerregistry.NewRefreshTokensClient(registryWithScheme.String()) refreshToken, err := repoClient.GetFromExchange(context.Background(), "access_token", registryURL, tenantID, "", accessToken.Token) if err != nil { return "", "", fmt.Errorf("failed to get refresh token: %w", err) } // we use a special username when authenticating with ACR using an access token // associated with a managed identity return "00000000-0000-0000-0000-000000000000", *refreshToken.RefreshToken, nil } 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") } ================================================ FILE: pkg/webhook/registryauth/registryauth.go ================================================ // // 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. package registryauth import ( "context" "io" ecr "github.com/awslabs/amazon-ecr-credential-helper/ecr-login" "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/authn/k8schain" kauth "github.com/google/go-containerregistry/pkg/authn/kubernetes" "github.com/google/go-containerregistry/pkg/v1/google" "github.com/sigstore/policy-controller/pkg/webhook/registryauth/azure" "k8s.io/client-go/kubernetes" ) /* This file is based the K8s auth key chain constructor defined in the go-containerregistry library in https://github.com/google/go-containerregistry/blob/ff385a972813c79bbd5fc89357ff2cefe3e5b43c/pkg/authn/k8schain/k8schain.go The ony difference in this implementation is the Azure key chain. It is created using the current Azure credential handler defined in github.com/Azure/azure-sdk-for-go/sdk/azidentity. The K8s auth key chain constructor in go-containerregistry uses an old Azure credential handler. We should eventually try to get the Azure credential handler updated upstream in go-containerregistry and remove this file. But for now, this custom constructor should fix authentication errors encountered when using the policy controller with ACR and AKS clusters. */ var amazonKeychain authn.Keychain = authn.NewKeychainFromHelper(ecr.NewECRHelper(ecr.WithLogger(io.Discard))) func NewK8sKeychain(ctx context.Context, client kubernetes.Interface, opt k8schain.Options) (authn.Keychain, error) { k8s, err := kauth.New(ctx, client, opt) if err != nil { return nil, err } return authn.NewMultiKeychain( k8s, authn.DefaultKeychain, google.Keychain, amazonKeychain, authn.NewKeychainFromHelper(azure.NewACRHelper()), ), nil } ================================================ FILE: pkg/webhook/testdata/cert.pem ================================================ -----BEGIN CERTIFICATE----- MIHwMIGXoAMCAQICAQEwCgYIKoZIzj0EAwIwADAiGA8wMDAxMDEwMTAwMDAwMFoY DzAwMDEwMTAxMDAwMDAwWjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMP4j 1NMREAE3IpA1ihHN1xZFThO4oFdeRWbVTIUDhgOcCDVh5K/pmquzDE3uqG1D9TmZ wC5pPyURDgJ9dzTvjDAKBggqhkjOPQQDAgNIADBFAiEAtCfQlhemMkHHz+Brj9ls f1iHbBF+q2r9Ijud52yFeYoCIESU129jdhqmhm1yWb0bI95dCTEaiKLZaQ8mK+OV 1yr2 -----END CERTIFICATE----- ================================================ FILE: pkg/webhook/validation.go ================================================ // // Copyright 2021 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. package webhook import ( "context" "crypto" "encoding/json" "encoding/pem" "fmt" "io" "strings" "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" "knative.dev/pkg/logging" "github.com/sigstore/cosign/v3/pkg/cosign" "github.com/sigstore/cosign/v3/pkg/oci" ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" "github.com/sigstore/cosign/v3/pkg/oci/static" policycontrollerconfig "github.com/sigstore/policy-controller/pkg/config" "github.com/sigstore/sigstore/pkg/signature" ) func valid(ctx context.Context, ref name.Reference, keys []crypto.PublicKey, hashAlgo crypto.Hash, checkOpts *cosign.CheckOpts) ([]oci.Signature, error) { if len(keys) == 0 { return validSignatures(ctx, ref, checkOpts) } // We return nil if ANY key matches var lastErr error for _, k := range keys { verifier, err := signature.LoadVerifier(k, hashAlgo) if err != nil { logging.FromContext(ctx).Errorf("error creating verifier: %v", err) lastErr = err continue } checkOpts.SigVerifier = verifier sps, err := validSignatures(ctx, ref, checkOpts) if err != nil { logging.FromContext(ctx).Errorf("error validating signatures: %v", err) lastErr = err continue } return sps, nil } logging.FromContext(ctx).Debug("No valid signatures were found.") return nil, lastErr } // For testing var cosignVerifySignatures = cosign.VerifyImageSignatures var cosignVerifyAttestations = cosign.VerifyImageAttestations var ociremoteResolveDigest = ociremote.ResolveDigest var ociremoteReferrers = ociremote.Referrers var ociremoteSignedImage = ociremote.SignedImage var testProcessAttestationArtifact = processAttestationArtifact func validSignatures(ctx context.Context, ref name.Reference, checkOpts *cosign.CheckOpts) ([]oci.Signature, error) { checkOpts.ClaimVerifier = cosign.SimpleClaimVerifier sigs, _, err := cosignVerifySignatures(ctx, ref, checkOpts) return sigs, err } func validAttestations(ctx context.Context, ref name.Reference, checkOpts *cosign.CheckOpts) ([]oci.Signature, error) { cfg := policycontrollerconfig.FromContextOrDefaults(ctx) if cfg.EnableOCI11 { if attestations, err := discoverAttestationsOCI11(ctx, ref, checkOpts); err == nil { return attestations, nil } } checkOpts.ClaimVerifier = cosign.IntotoSubjectClaimVerifier attestations, _, err := cosignVerifyAttestations(ctx, ref, checkOpts) return attestations, err } func discoverAttestationsOCI11(ctx context.Context, ref name.Reference, checkOpts *cosign.CheckOpts) ([]oci.Signature, error) { digest, err := ociremoteResolveDigest(ref, checkOpts.RegistryClientOpts...) if err != nil { return nil, err } indexManifest, err := ociremoteReferrers(digest, "", checkOpts.RegistryClientOpts...) if err != nil { return nil, err } var allSigs []oci.Signature for _, manifest := range indexManifest.Manifests { if strings.Contains(manifest.ArtifactType, "in-toto") { sigs, err := testProcessAttestationArtifact(manifest, digest.Repository, checkOpts.RegistryClientOpts) if err != nil { logging.FromContext(ctx).Debugf("Failed to process attestation artifact: %v", err) continue } allSigs = append(allSigs, sigs...) } } if len(allSigs) == 0 { return nil, fmt.Errorf("no attestations found") } return allSigs, nil } func processAttestationArtifact(result v1.Descriptor, repository name.Repository, registryOpts []ociremote.Option) ([]oci.Signature, error) { attRef, err := name.ParseReference(fmt.Sprintf("%s@%s", repository, result.Digest.String())) if err != nil { return nil, err } signedEntity, err := ociremoteSignedImage(attRef, registryOpts...) if err != nil { return nil, err } layers, err := signedEntity.Layers() if err != nil || len(layers) == 0 { return nil, fmt.Errorf("no layers found") } rc, err := layers[0].Uncompressed() if err != nil { return nil, err } defer rc.Close() dsseEnvelope, err := io.ReadAll(rc) if err != nil { return nil, err } var envelope struct { Payload string `json:"payload"` Signatures []struct { Sig string `json:"sig"` } `json:"signatures"` } if err := json.Unmarshal(dsseEnvelope, &envelope); err != nil { return nil, err } var signatures []oci.Signature for _, sig := range envelope.Signatures { payloadStruct := map[string]interface{}{ "payload": envelope.Payload, } payloadBytes, _ := json.Marshal(payloadStruct) if ociSig, err := static.NewSignature(payloadBytes, sig.Sig); err == nil { signatures = append(signatures, ociSig) } } return signatures, nil } func parsePems(b []byte) []*pem.Block { p, rest := pem.Decode(b) if p == nil { return nil } pems := []*pem.Block{p} if rest != nil { return append(pems, parsePems(rest)...) } return pems } ================================================ FILE: pkg/webhook/validator.go ================================================ // // Copyright 2021 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. package webhook import ( "bytes" "context" "crypto/ecdsa" "crypto/sha256" "crypto/x509" "encoding/hex" "encoding/json" "errors" "fmt" "strings" "sync" "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/authn/k8schain" "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/google/go-containerregistry/pkg/v1/types" "github.com/sigstore/cosign/v3/pkg/cosign" "github.com/sigstore/cosign/v3/pkg/oci" ociremote "github.com/sigstore/cosign/v3/pkg/oci/remote" "github.com/sigstore/cosign/v3/pkg/policy" "github.com/sigstore/policy-controller/pkg/apis/config" policyduckv1beta1 "github.com/sigstore/policy-controller/pkg/apis/duck/v1beta1" policycontrollerconfig "github.com/sigstore/policy-controller/pkg/config" pctuf "github.com/sigstore/policy-controller/pkg/tuf" webhookcip "github.com/sigstore/policy-controller/pkg/webhook/clusterimagepolicy" "github.com/sigstore/policy-controller/pkg/webhook/registryauth" rekor "github.com/sigstore/rekor/pkg/client" "github.com/sigstore/rekor/pkg/generated/client" "github.com/sigstore/sigstore-go/pkg/root" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/fulcioroots" "github.com/sigstore/sigstore/pkg/signature" "github.com/sigstore/sigstore/pkg/tuf" admissionv1 "k8s.io/api/admission/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" kubeclient "knative.dev/pkg/client/injection/kube/client" "knative.dev/pkg/logging" ) type Validator struct{} func NewValidator(_ context.Context) *Validator { return &Validator{} } // isDeletedOrStatusUpdate returns true if the resource in question is being // deleted, is already deleted or Status is being updated. In any of those // cases, we do not validate the resource func isDeletedOrStatusUpdate(ctx context.Context, deletionTimestamp *metav1.Time) bool { return apis.IsInDelete(ctx) || deletionTimestamp != nil || apis.IsInStatusUpdate(ctx) } // This is attached to contexts passed to webhook methods so that if the // user wants to get the Spec for the PolicyResult we can attach it. type includeSpecKey struct{} // IncludeSpec adds the spec to context so it's later available for // inclusion in PolicyResult. This is safe to call multiple times, first // one "wins". This is on purpose so that since we call down the various // levels and we want the highest resource level to be available, otherwise // everything boils down to PodSpec and it's lossy then. func IncludeSpec(ctx context.Context, spec interface{}) context.Context { if GetIncludeSpec(ctx) == nil { return context.WithValue(ctx, includeSpecKey{}, spec) } return ctx } // GetIncludeSpec returns the highest level spec for a resource possible. // For example, for Deployment it would return Deployment.Spec func GetIncludeSpec(ctx context.Context) interface{} { return ctx.Value(includeSpecKey{}) } // This is attached to contexts passed to webhook methods so that if the // user wants to get the ObjectMeta for the PolicyResult we can attach it. type includeObjectMetaKey struct{} // This is attached to contexts passed to webhook methods so that if the // user wants to get the TypeMeta for the PolicyResult we can attach it. type includeTypeMetaKey struct{} // IncludeObjectMeta adds the ObjectMeta to context so it's later available for // inclusion in PolicyResult. This is safe to call multiple times, first // one "wins". This is on purpose so that since we call down the various // levels and we want the highest resource level to be available, otherwise // everything boils down to PodSpec and it's lossy then. func IncludeObjectMeta(ctx context.Context, meta interface{}) context.Context { if GetIncludeObjectMeta(ctx) == nil { return context.WithValue(ctx, includeObjectMetaKey{}, meta) } return ctx } // GetIncludeObjectMeta returns the highest level ObjectMeta for a resource // possible. For example, for Deployment it would return Deployment.Spec func GetIncludeObjectMeta(ctx context.Context) interface{} { return ctx.Value(includeObjectMetaKey{}) } // IncludeTypeMeta adds the TypeMeta to context so it's later available for // inclusion in PolicyResult. This is safe to call multiple times, first // one "wins". This is on purpose so that since we call down the various // levels and we want the highest resource level to be available, otherwise // everything boils down to PodSpec and it's lossy then. func IncludeTypeMeta(ctx context.Context, meta interface{}) context.Context { if GetIncludeTypeMeta(ctx) == nil { return context.WithValue(ctx, includeTypeMetaKey{}, meta) } return ctx } // GetIncludeTypeMeta returns the highest level TypeMeta for a resource // possible. For example, for Deployment it would return: // apiVersion: apps/v1 // kind: Deployment func GetIncludeTypeMeta(ctx context.Context) interface{} { return ctx.Value(includeTypeMetaKey{}) } // ValidatePodScalable implements policyduckv1beta1.PodScalableValidator // It is very similar to ValidatePodSpecable, but allows for spec.replicas // to be decremented. This allows for scaling down pods with non-compliant // images that would otherwise be forbidden. func (v *Validator) ValidatePodScalable(ctx context.Context, ps *policyduckv1beta1.PodScalable) *apis.FieldError { // If we are deleting (or already deleted) or updating status, don't block. if isDeletedOrStatusUpdate(ctx, ps.DeletionTimestamp) { return nil } // If we are being scaled down don't block it. if ps.IsScalingDown(ctx) { logging.FromContext(ctx).Debugf("Skipping validations due to scale down request %s/%s", &ps.Name, &ps.Namespace) return nil } // Attach the spec for down the line to be attached if it's required by // policy to be included in the PolicyResult. ctx = IncludeSpec(ctx, ps.Spec) ctx = IncludeObjectMeta(ctx, ps.ObjectMeta) ctx = IncludeTypeMeta(ctx, ps.TypeMeta) imagePullSecrets := make([]string, 0, len(ps.Spec.Template.Spec.ImagePullSecrets)) for _, s := range ps.Spec.Template.Spec.ImagePullSecrets { imagePullSecrets = append(imagePullSecrets, s.Name) } ns := getNamespace(ctx, ps.Namespace) opt := k8schain.Options{ Namespace: ns, ServiceAccountName: ps.Spec.Template.Spec.ServiceAccountName, ImagePullSecrets: imagePullSecrets, } return v.validatePodSpec(ctx, ns, ps.Kind, ps.APIVersion, ps.ObjectMeta.Labels, &ps.Spec.Template.Spec, opt).ViaField("spec.template.spec") } // ValidatePodSpecable implements duckv1.PodSpecValidator func (v *Validator) ValidatePodSpecable(ctx context.Context, wp *duckv1.WithPod) *apis.FieldError { // If we are deleting (or already deleted) or updating status, don't block. if isDeletedOrStatusUpdate(ctx, wp.DeletionTimestamp) { return nil } // Attach the spec/metadata for down the line to be attached if it's // required by policy to be included in the PolicyResult. ctx = IncludeSpec(ctx, wp.Spec) ctx = IncludeObjectMeta(ctx, wp.ObjectMeta) ctx = IncludeTypeMeta(ctx, wp.TypeMeta) imagePullSecrets := make([]string, 0, len(wp.Spec.Template.Spec.ImagePullSecrets)) for _, s := range wp.Spec.Template.Spec.ImagePullSecrets { imagePullSecrets = append(imagePullSecrets, s.Name) } ns := getNamespace(ctx, wp.Namespace) opt := k8schain.Options{ Namespace: ns, ServiceAccountName: wp.Spec.Template.Spec.ServiceAccountName, ImagePullSecrets: imagePullSecrets, } return v.validatePodSpec(ctx, ns, wp.Kind, wp.APIVersion, wp.ObjectMeta.Labels, &wp.Spec.Template.Spec, opt).ViaField("spec.template.spec") } // ValidatePod implements duckv1.PodValidator func (v *Validator) ValidatePod(ctx context.Context, p *duckv1.Pod) *apis.FieldError { // If we are deleting (or already deleted) or updating status, don't block. if isDeletedOrStatusUpdate(ctx, p.DeletionTimestamp) { return nil } // Attach the spec/metadata for down the line to be attached if it's // required by policy to be included in the PolicyResult. ctx = IncludeSpec(ctx, p.Spec) ctx = IncludeObjectMeta(ctx, p.ObjectMeta) imagePullSecrets := make([]string, 0, len(p.Spec.ImagePullSecrets)) for _, s := range p.Spec.ImagePullSecrets { imagePullSecrets = append(imagePullSecrets, s.Name) } ns := getNamespace(ctx, p.Namespace) opt := k8schain.Options{ Namespace: ns, ServiceAccountName: p.Spec.ServiceAccountName, ImagePullSecrets: imagePullSecrets, } return v.validatePodSpec(ctx, ns, p.Kind, p.APIVersion, p.ObjectMeta.Labels, &p.Spec, opt).ViaField("spec") } // ValidateCronJob implements duckv1.CronJobValidator func (v *Validator) ValidateCronJob(ctx context.Context, c *duckv1.CronJob) *apis.FieldError { // If we are deleting (or already deleted) or updating status, don't block. if isDeletedOrStatusUpdate(ctx, c.DeletionTimestamp) { return nil } // Attach the spec/metadata for down the line to be attached if it's // required by policy to be included in the PolicyResult. ctx = IncludeSpec(ctx, c.Spec) ctx = IncludeObjectMeta(ctx, c.ObjectMeta) ctx = IncludeTypeMeta(ctx, c.TypeMeta) imagePullSecrets := make([]string, 0, len(c.Spec.JobTemplate.Spec.Template.Spec.ImagePullSecrets)) for _, s := range c.Spec.JobTemplate.Spec.Template.Spec.ImagePullSecrets { imagePullSecrets = append(imagePullSecrets, s.Name) } ns := getNamespace(ctx, c.Namespace) opt := k8schain.Options{ Namespace: ns, ServiceAccountName: c.Spec.JobTemplate.Spec.Template.Spec.ServiceAccountName, ImagePullSecrets: imagePullSecrets, } return v.validatePodSpec(ctx, ns, c.Kind, c.APIVersion, c.ObjectMeta.Labels, &c.Spec.JobTemplate.Spec.Template.Spec, opt).ViaField("spec.jobTemplate.spec.template.spec") } func (v *Validator) validatePodSpec(ctx context.Context, namespace, kind, apiVersion string, labels map[string]string, ps *corev1.PodSpec, opt k8schain.Options) (errs *apis.FieldError) { kc, err := registryauth.NewK8sKeychain(ctx, kubeclient.Get(ctx), opt) if err != nil { logging.FromContext(ctx).Warnf("Unable to build k8schain: %v", err) return apis.ErrGeneric(err.Error(), apis.CurrentField) } type containerCheckResult struct { index int containerCheckResult *apis.FieldError } checkContainers := func(cs []corev1.Container, field string) { results := make(chan containerCheckResult, len(cs)) wg := new(sync.WaitGroup) for i, c := range cs { i := i c := c wg.Add(1) go func() { defer wg.Done() // Require digests, otherwise the validation is meaningless // since the tag can move. fe := refOrFieldError(c.Image, field, i) if fe != nil { results <- containerCheckResult{index: i, containerCheckResult: fe} return } containerErrors := v.validateContainerImage(ctx, c.Image, namespace, field, i, kind, apiVersion, labels, kc, ociremote.WithRemoteOptions( remote.WithContext(ctx), remote.WithAuthFromKeychain(kc), )) results <- containerCheckResult{index: i, containerCheckResult: containerErrors} }() } for i := 0; i < len(cs); i++ { select { case <-ctx.Done(): errs = errs.Also(apis.ErrGeneric("context was canceled before validation completed")) case result, ok := <-results: if !ok { errs = errs.Also(apis.ErrGeneric("results channel failed to produce a result")) } else { errs = errs.Also(result.containerCheckResult) } } } wg.Wait() } checkEphemeralContainers := func(cs []corev1.EphemeralContainer, field string) { results := make(chan containerCheckResult, len(cs)) wg := new(sync.WaitGroup) for i, c := range cs { i := i c := c wg.Add(1) go func() { defer wg.Done() // Require digests, otherwise the validation is meaningless // since the tag can move. fe := refOrFieldError(c.Image, field, i) if fe != nil { results <- containerCheckResult{index: i, containerCheckResult: fe} return } containerErrors := v.validateContainerImage(ctx, c.Image, namespace, field, i, kind, apiVersion, labels, kc, ociremote.WithRemoteOptions( remote.WithContext(ctx), remote.WithAuthFromKeychain(kc), )) results <- containerCheckResult{index: i, containerCheckResult: containerErrors} }() } for i := 0; i < len(cs); i++ { select { case <-ctx.Done(): errs = errs.Also(apis.ErrGeneric("context was canceled before validation completed")) case result, ok := <-results: if !ok { errs = errs.Also(apis.ErrGeneric("results channel failed to produce a result")) } else { errs = errs.Also(result.containerCheckResult) } } } wg.Wait() } checkContainers(ps.InitContainers, "initContainers") checkContainers(ps.Containers, "containers") checkEphemeralContainers(ps.EphemeralContainers, "ephemeralContainers") return errs } // setNoMatchingPoliciesError returns nil if the no matching policies behaviour // has been set to allow or has not been set. Otherwise returns either a warning // or error based on the NoMatchPolicy. func setNoMatchingPoliciesError(ctx context.Context, image, field string, index int) *apis.FieldError { // Check what the configuration is and act accordingly. pcConfig := policycontrollerconfig.FromContextOrDefaults(ctx) noMatchingPolicyError := apis.ErrGeneric("no matching policies", "image").ViaFieldIndex(field, index) noMatchingPolicyError.Details = image if pcConfig == nil { // This should not happen, but handle it as fail close return noMatchingPolicyError } switch pcConfig.NoMatchPolicy { case policycontrollerconfig.AllowAll: // Allow it through, nothing to do. return nil case policycontrollerconfig.DenyAll: logging.FromContext(ctx).Errorf("no matching policies for image %s", image) return noMatchingPolicyError case policycontrollerconfig.WarnAll: logging.FromContext(ctx).Warnf("no matching policies for image %s", image) return noMatchingPolicyError.At(apis.WarningLevel) default: // Fail closed. return noMatchingPolicyError } } // validatePolicies will go through all the matching Policies and their // Authorities for a given image. Returns the map of policy=>Validated // signatures. From the map you can see the number of matched policies along // with the signatures that were verified. // If there's a policy that did not match, it will be returned in the errors map // along with all the errors that caused it to fail. // Note that if an image does not match any policies, it's perfectly // reasonable that the return value is 0, nil since there were no errors, but // the image was not validated against any matching policy and hence authority. func validatePolicies(ctx context.Context, namespace string, ref name.Reference, policies map[string]webhookcip.ClusterImagePolicy, kc authn.Keychain, remoteOpts ...ociremote.Option) (map[string]*PolicyResult, map[string][]error) { type retChannelType struct { name string policyResult *PolicyResult errors []error } results := make(chan retChannelType, len(policies)) wg := new(sync.WaitGroup) // For each matching policy it must validate at least one Authority within // it. // From the Design document, the part about multiple Policies matching: // "If multiple policies match a particular image, then ALL of those // policies must be satisfied for the image to be admitted." // If none of the Authorities for a given policy pass the checks, gather // the errors here. If one passes, do not return the errors. for cipName, cip := range policies { // Due to running in gofunc cipName := cipName cip := cip logging.FromContext(ctx).Debugf("Checking Policy: %s", cipName) wg.Add(1) go func() { defer wg.Done() result := retChannelType{name: cipName} result.policyResult, result.errors = ValidatePolicy(ctx, namespace, ref, cip, kc, remoteOpts...) // Cache the result. FromContext(ctx).Set(ctx, ref.Name(), cipName, string(cip.UID), cip.ResourceVersion, &CacheResult{ PolicyResult: result.policyResult, Errors: result.errors, }) results <- result }() } // Gather all validated policies here. policyResults := make(map[string]*PolicyResult) // For a policy that does not pass at least one authority, gather errors // here so that we can give meaningful errors to the user. ret := map[string][]error{} for i := 0; i < len(policies); i++ { select { case <-ctx.Done(): ret["internalerror"] = append(ret["internalerror"], fmt.Errorf("context was canceled before validation completed")) case result, ok := <-results: if !ok { ret["internalerror"] = append(ret["internalerror"], fmt.Errorf("results channel failed to produce a result")) continue } switch { // Return AuthorityMatches before errors, since even if there // are errors, if there are 0 or more authorities that match, // it will pass the Policy. Of course, a CIP level policy can // override this behaviour, but that has been checked above and // if it failed, it will nil out the policyResult. case result.policyResult != nil: policyResults[result.name] = result.policyResult case len(result.errors) > 0: ret[result.name] = append(ret[result.name], result.errors...) default: ret[result.name] = append(ret[result.name], fmt.Errorf("failed to process policy: %s", result.name)) } } } wg.Wait() return policyResults, ret } func asFieldError(warn bool, err error) *apis.FieldError { r := &apis.FieldError{Message: err.Error()} if warn { return r.At(apis.WarningLevel) } return r.At(apis.ErrorLevel) } // ValidatePolicy will go through all the Authorities for a given image/policy // and return validated authorities if at least one of the Authorities // validated the signatures OR attestations if atttestations were specified. // Returns PolicyResult if one or more authorities matched, otherwise nil. // In any case returns all errors encountered if none of the authorities // passed. // kc is the Keychain to use for fetching ConfigFile that's independent of the // signatures / attestations. func ValidatePolicy(ctx context.Context, namespace string, ref name.Reference, cip webhookcip.ClusterImagePolicy, kc authn.Keychain, remoteOpts ...ociremote.Option) (*PolicyResult, []error) { // Check the cache and return if hit, otherwise, check the policy cacheResult := FromContext(ctx).Get(ctx, ref.String(), string(cip.UID), cip.ResourceVersion) if cacheResult != nil { return cacheResult.PolicyResult, cacheResult.Errors } // Each gofunc creates and puts one of these into a results channel. // Once each gofunc finishes, we go through the channel and pull out // the results. type retChannelType struct { name string static bool attestations map[string][]PolicyAttestation signatures []PolicySignature err error } wg := new(sync.WaitGroup) results := make(chan retChannelType, len(cip.Authorities)) for _, authority := range cip.Authorities { authority := authority // due to gofunc logging.FromContext(ctx).Debugf("Checking Authority: %s\n", authority.Name) wg.Add(1) go func() { defer wg.Done() result := retChannelType{name: authority.Name} // Assignment for appendAssign lint error authorityRemoteOpts := remoteOpts authorityRemoteOpts = append(authorityRemoteOpts, authority.RemoteOpts...) signaturePullSecretsOpts, err := authority.SourceSignaturePullSecretsOpts(ctx, namespace) if err != nil { result.err = err results <- result return } authorityRemoteOpts = append(authorityRemoteOpts, signaturePullSecretsOpts...) switch { case authority.Static != nil: if authority.Static.Action == "fail" { result.err = fmt.Errorf("disallowed by static policy: %s", authority.Static.Message) results <- result return } result.static = true case len(authority.Attestations) > 0: // We're doing the verify-attestations path, so validate (.att) result.attestations, result.err = ValidatePolicyAttestationsForAuthority(ctx, ref, authority, authorityRemoteOpts...) default: result.signatures, result.err = ValidatePolicySignaturesForAuthority(ctx, ref, authority, authorityRemoteOpts...) } results <- result }() } // If none of the Authorities for a given policy pass the checks, gather // the errors here. Even if there are errors, return the matched // authoritypolicies. authorityErrors := make([]error, 0, len(cip.Authorities)) // We collect all the successfully satisfied Authorities into this and // return it. policyResult := &PolicyResult{ AuthorityMatches: make(map[string]AuthorityMatch, len(cip.Authorities)), } for range cip.Authorities { select { case <-ctx.Done(): authorityErrors = append(authorityErrors, fmt.Errorf("%w before validation completed", ctx.Err())) case result, ok := <-results: if !ok { authorityErrors = append(authorityErrors, errors.New("results channel closed before all results were sent")) continue } switch { case result.err != nil: // We only wrap actual policy failures as FieldErrors with the // possibly Warn level. Other things imho should be still // be considered errors. authorityErrors = append(authorityErrors, asFieldError(cip.Mode == "warn", result.err)) case len(result.signatures) > 0: policyResult.AuthorityMatches[result.name] = AuthorityMatch{Signatures: result.signatures} case len(result.attestations) > 0: policyResult.AuthorityMatches[result.name] = AuthorityMatch{Attestations: result.attestations} case result.static: // This happens when we encounter a policy with: // static: // action: "pass" policyResult.AuthorityMatches[result.name] = AuthorityMatch{ Static: true, } default: authorityErrors = append(authorityErrors, fmt.Errorf("failed to process authority: %s", result.name)) } } } wg.Wait() // Even if there are errors, return the policies, since as per the // spec, we just need one authority to pass checks. If more than // one are required, that is enforced at the CIP policy level. // If however there are no authorityMatches, return nil so we don't have // to keep checking the length on the returned calls. if len(policyResult.AuthorityMatches) == 0 { return nil, authorityErrors } // Ok, there's at least one valid authority that matched. If there's a CIP // level policy, validate it here before returning. if cip.Policy != nil { if cip.Policy.FetchConfigFile != nil && *cip.Policy.FetchConfigFile { logging.FromContext(ctx).Debug("Fetching ConfigFiles") // It's unfortunate that we have to keep having the kc here. It // would be nice if we could just unwrap/generate the ggcr remote // options from the oci remote options, but for now this is how // we're rolling. rOpts := []remote.Option{ remote.WithContext(ctx), remote.WithAuthFromKeychain(kc), } configFiles, errs := getConfigs(ctx, ref, rOpts...) if len(errs) > 0 { for _, e := range errs { authorityErrors = append(authorityErrors, asFieldError(cip.Mode == "warn", e)) } return nil, authorityErrors } policyResult.Config = configFiles } if cip.Policy.IncludeSpec != nil && *cip.Policy.IncludeSpec { policyResult.Spec = GetIncludeSpec(ctx) } if cip.Policy.IncludeObjectMeta != nil && *cip.Policy.IncludeObjectMeta { policyResult.ObjectMeta = GetIncludeObjectMeta(ctx) } if cip.Policy.IncludeTypeMeta != nil && *cip.Policy.IncludeTypeMeta { policyResult.TypeMeta = GetIncludeTypeMeta(ctx) } logging.FromContext(ctx).Info("Validating CIP level policy") policyJSON, err := json.Marshal(policyResult) if err != nil { return nil, append(authorityErrors, err) } logging.FromContext(ctx).Infof("CIP level policy: %s", string(policyJSON)) warn, err := policy.EvaluatePolicyAgainstJSON(ctx, "ClusterImagePolicy", cip.Policy.Type, cip.Policy.Data, policyJSON) if err != nil { logging.FromContext(ctx).Warnf("Failed to validate CIP level policy; err: %w; against %s", err, string(policyJSON)) return nil, append(authorityErrors, asFieldError(cip.Mode == "warn", err)) } if warn != nil { logging.FromContext(ctx).Warnf("Failed to validate CIP level policy; warn: %w; against %s", warn, string(policyJSON)) return nil, append(authorityErrors, asFieldError(cip.Mode == "warn", warn)) } } return policyResult, authorityErrors } func ociSignatureToPolicySignature(ctx context.Context, sigs []oci.Signature) []PolicySignature { ret := make([]PolicySignature, 0, len(sigs)) for _, ociSig := range sigs { logging.FromContext(ctx).Debugf("Converting signature %+v", ociSig) sigID, err := signatureID(ociSig) if err != nil { logging.FromContext(ctx).Debugf("Error fetching signature %+v", err) continue } if cert, err := ociSig.Cert(); err == nil && cert != nil { ce := cosign.CertExtensions{ Cert: cert, } sub := "" if sans := cryptoutils.GetSubjectAlternateNames(cert); len(sans) > 0 { sub = sans[0] } ret = append(ret, PolicySignature{ ID: sigID, Subject: sub, Issuer: ce.GetIssuer(), GithubExtensions: GithubExtensions{ WorkflowTrigger: ce.GetCertExtensionGithubWorkflowTrigger(), WorkflowSHA: ce.GetExtensionGithubWorkflowSha(), WorkflowName: ce.GetCertExtensionGithubWorkflowName(), WorkflowRepo: ce.GetCertExtensionGithubWorkflowRepository(), WorkflowRef: ce.GetCertExtensionGithubWorkflowRef(), }, }) } else { ret = append(ret, PolicySignature{ ID: sigID, // TODO(mattmoor): Is there anything we should encode for key-based? }) } } return ret } // signatureID creates a unique hash for the Signature, using both the signature itself + the cert. func signatureID(sig oci.Signature) (string, error) { h := sha256.New() s, err := sig.Signature() if err != nil { return "", err } if _, err := h.Write(s); err != nil { return "", err } cert, err := sig.Cert() if err != nil { return "", err } if cert != nil { c, err := cryptoutils.MarshalCertificateToPEM(cert) if err != nil { return "", err } if _, err := h.Write(c); err != nil { return "", err } } return hex.EncodeToString(h.Sum(nil)), nil } // attestation is used to accumulate the signature along with extracted and // validated metadata during validation to construct a list of // PolicyAttestations upon completion without needing to refetch any of the // parts. type attestation struct { oci.Signature PredicateType string Payload []byte Digest string } func attestationToPolicyAttestations(ctx context.Context, atts []attestation) []PolicyAttestation { ret := make([]PolicyAttestation, 0, len(atts)) for _, att := range atts { logging.FromContext(ctx).Debugf("Converting attestation with digest %s\n", att.Digest) sigID, err := signatureID(att.Signature) if err != nil { logging.FromContext(ctx).Debugf("Error fetching attestation signature %+v", err) continue } if cert, err := att.Cert(); err == nil && cert != nil { ce := cosign.CertExtensions{ Cert: cert, } sub := "" if sans := cryptoutils.GetSubjectAlternateNames(cert); len(sans) > 0 { sub = sans[0] } ret = append(ret, PolicyAttestation{ PolicySignature: PolicySignature{ ID: sigID, Subject: sub, Issuer: ce.GetIssuer(), GithubExtensions: GithubExtensions{ WorkflowTrigger: ce.GetCertExtensionGithubWorkflowTrigger(), WorkflowSHA: ce.GetExtensionGithubWorkflowSha(), WorkflowName: ce.GetCertExtensionGithubWorkflowName(), WorkflowRepo: ce.GetCertExtensionGithubWorkflowRepository(), WorkflowRef: ce.GetCertExtensionGithubWorkflowRef(), }, }, Digest: att.Digest, PredicateType: att.PredicateType, Payload: att.Payload, }) } else { ret = append(ret, PolicyAttestation{ PolicySignature: PolicySignature{ ID: sigID, // TODO(mattmoor): Is there anything we should encode for key-based? }, PredicateType: att.PredicateType, Payload: att.Payload, Digest: att.Digest, }) } } return ret } // ValidatePolicySignaturesForAuthority takes the Authority and tries to // verify a signature against it. func ValidatePolicySignaturesForAuthority(ctx context.Context, ref name.Reference, authority webhookcip.Authority, remoteOpts ...ociremote.Option) ([]PolicySignature, error) { name := authority.Name checkOpts, err := checkOptsFromAuthority(ctx, authority, remoteOpts...) if err != nil { logging.FromContext(ctx).Errorf("failed constructing checkOpts for %s: +v", name, err) return nil, fmt.Errorf("constructing checkOpts for %s: %w", name, err) } switch { case authority.Key != nil: if len(authority.Key.PublicKeys) == 0 { return nil, fmt.Errorf("there are no public keys for authority %s", name) } // TODO(vaikas): What should happen if there are multiple keys // Is it even allowed? 'valid' returns success if any key // matches. // https://github.com/sigstore/policy-controller/issues/1652 sps, err := valid(ctx, ref, authority.Key.PublicKeys, authority.Key.HashAlgorithmCode, checkOpts) if err != nil { return nil, fmt.Errorf("signature key validation failed for authority %s for %s: %w", name, ref.Name(), err) } logging.FromContext(ctx).Debugf("validated signature for %s for authority %s got %d signatures", ref.Name(), authority.Name, len(sps)) return ociSignatureToPolicySignature(ctx, sps), nil case authority.Keyless != nil: if authority.Keyless.URL != nil { sps, err := validSignatures(ctx, ref, checkOpts) if err != nil { logging.FromContext(ctx).Errorf("failed validSignatures for authority %s with fulcio for %s: %v", name, ref.Name(), err) return nil, fmt.Errorf("signature keyless validation failed for authority %s for %s: %w", name, ref.Name(), err) } logging.FromContext(ctx).Debugf("validated signature for %s, got %d signatures", ref.Name(), len(sps)) return ociSignatureToPolicySignature(ctx, sps), nil } return nil, fmt.Errorf("no Keyless URL specified") case authority.RFC3161Timestamp != nil: sps, err := validSignatures(ctx, ref, checkOpts) if err != nil { logging.FromContext(ctx).Errorf("failed validSignatures for authority %s with fulcio for %s: %v", name, ref.Name(), err) return nil, fmt.Errorf("signature TSA validation failed for authority %s for %s: %w", name, ref.Name(), err) } logging.FromContext(ctx).Debugf("validated TSA signature for %s, got %d signatures", ref.Name(), len(sps)) return ociSignatureToPolicySignature(ctx, sps), nil } // This should never happen because authority has to have been validated to // be either having a Key, Keyless, or Static (handled elsewhere) return nil, errors.New("authority has neither key, keyless, or static specified") } // ValidatePolicyAttestationsForAuthority takes the Authority and tries to // verify attestations against it. func ValidatePolicyAttestationsForAuthority(ctx context.Context, ref name.Reference, authority webhookcip.Authority, remoteOpts ...ociremote.Option) (map[string][]PolicyAttestation, error) { name := authority.Name checkOpts, err := checkOptsFromAuthority(ctx, authority, remoteOpts...) if err != nil { logging.FromContext(ctx).Errorf("failed creating checkopts client: %v", err) return nil, fmt.Errorf("creating CheckOpts: %w", err) } verifiedAttestations := []oci.Signature{} switch { case authority.Key != nil && len(authority.Key.PublicKeys) > 0: for _, k := range authority.Key.PublicKeys { verifier, err := signature.LoadVerifier(k, authority.Key.HashAlgorithmCode) if err != nil { logging.FromContext(ctx).Errorf("error creating verifier: %v", err) return nil, fmt.Errorf("creating verifier: %w", err) } checkOpts.SigVerifier = verifier va, err := validAttestations(ctx, ref, checkOpts) if err != nil { logging.FromContext(ctx).Errorf("error validating attestations: %v", err) return nil, fmt.Errorf("attestation key validation failed for authority %s for %s: %w", name, ref.Name(), err) } verifiedAttestations = append(verifiedAttestations, va...) } case authority.Keyless != nil: if authority.Keyless != nil && authority.Keyless.URL != nil { va, err := validAttestations(ctx, ref, checkOpts) if err != nil { logging.FromContext(ctx).Errorf("failed validAttestationsWithFulcio for authority %s with fulcio for %s: %v", name, ref.Name(), err) return nil, fmt.Errorf("attestation keyless validation failed for authority %s for %s: %w", name, ref.Name(), err) } verifiedAttestations = append(verifiedAttestations, va...) } case authority.RFC3161Timestamp != nil: va, err := validAttestations(ctx, ref, checkOpts) if err != nil { logging.FromContext(ctx).Errorf("failed validAttestations for authority %s with fulcio for %s: %v", name, ref.Name(), err) return nil, fmt.Errorf("signature TSA validAttestations failed for authority %s for %s: %w", name, ref.Name(), err) } logging.FromContext(ctx).Debugf("validated TSA signature for %s, got %d signatures", ref.Name(), len(va)) verifiedAttestations = append(verifiedAttestations, va...) } // If we didn't get any verified attestations either from the Key or Keyless // path, then error out if len(verifiedAttestations) == 0 { logging.FromContext(ctx).Errorf("no valid attestations found for authority %s for %s", name, ref.Name()) return nil, fmt.Errorf("%s for authority %s for %s", "no matching attestations", name, ref.Name()) } logging.FromContext(ctx).Debugf("Found %d valid attestations, validating policies for them", len(verifiedAttestations)) // Now spin through the Attestations that the user specified and validate // them. // TODO(vaikas): Pretty inefficient here, figure out a better way if // possible. ret := make(map[string][]PolicyAttestation, len(authority.Attestations)) // Keep track of all the predicate types that we checked so that we can // provide the user with a helpful error message in cases where the // precicateType specified is not found (typoed, using different than // expected, etc.). // We keep these in the map since there can be duplicates, so just use // map as uniquifier. checkedPredicateTypes := map[string]struct{}{} for _, wantedAttestation := range authority.Attestations { // Since there can be multiple verified attestations that matched, for // example multiple 'custom' attestations. We keep the first error that // we encounter here but do not exit on it, in case another attestation // satisfies the policy. var reterror error // There's a particular type, so we need to go through all the verified // attestations and make sure that our particular one is satisfied. checkedAttestations := make([]attestation, 0, len(verifiedAttestations)) for _, va := range verifiedAttestations { attDigest, err := va.Digest() if err != nil { logging.FromContext(ctx).Errorf("failed to get the attestation digest for %s: %v", wantedAttestation.Name, err) continue } attBytes, gotPredicateType, err := policy.AttestationToPayloadJSON(ctx, wantedAttestation.PredicateType, va) if gotPredicateType != "" { checkedPredicateTypes[gotPredicateType] = struct{}{} } if err != nil { if reterror == nil { // Only stash the first error reterror = err } logging.FromContext(ctx).Warnf("failed to convert attestation payload to json: %v", err) continue } if attBytes == nil { // This happens when we ask for a predicate type that this // attestation is not for. It's not an error, so we skip it. continue } if wantedAttestation.Type != "" { if warn, err := policy.EvaluatePolicyAgainstJSON(ctx, wantedAttestation.Name, wantedAttestation.Type, wantedAttestation.Data, attBytes); err != nil || warn != nil { if reterror == nil { // Only stash the first error reterror = err if err == nil { reterror = warn } } logging.FromContext(ctx).Warnf("failed policy validation for %s: %v", wantedAttestation.Name, err) continue } } logging.FromContext(ctx).Debugf("found verified attestation with digest: %s\n", attDigest.String()) // Ok, so this passed aok, jot it down to our result set as // verified attestation with the predicate type match checkedAttestations = append(checkedAttestations, attestation{ Signature: va, PredicateType: wantedAttestation.PredicateType, Payload: attBytes, Digest: attDigest.String(), }) } if len(checkedAttestations) == 0 { if reterror != nil { // If there was a matching policy, but it failed to be validated // then return that more specific error instead of the more // generic 'no matching attestations'. return nil, reterror } cpt := make([]string, 0, len(checkedPredicateTypes)) for pt := range checkedPredicateTypes { cpt = append(cpt, pt) } return nil, fmt.Errorf("%s with type %s, checked the following predicateTypes: %q", "no matching attestations", wantedAttestation.PredicateType, strings.Join(cpt, ",")) } ret[wantedAttestation.Name] = attestationToPolicyAttestations(ctx, checkedAttestations) } return ret, nil } // ResolvePodScalable implements policyduckv1beta1.PodScalableValidator func (v *Validator) ResolvePodScalable(ctx context.Context, ps *policyduckv1beta1.PodScalable) { // Don't mess with things that are being deleted or already deleted or // if status is being updated if isDeletedOrStatusUpdate(ctx, ps.DeletionTimestamp) { return } if ps.IsScalingDown(ctx) { logging.FromContext(ctx).Debugf("Skipping validations due to scale down request %s/%s", &ps.Name, &ps.Namespace) return } imagePullSecrets := make([]string, 0, len(ps.Spec.Template.Spec.ImagePullSecrets)) for _, s := range ps.Spec.Template.Spec.ImagePullSecrets { imagePullSecrets = append(imagePullSecrets, s.Name) } opt := k8schain.Options{ Namespace: getNamespace(ctx, ps.Namespace), ServiceAccountName: ps.Spec.Template.Spec.ServiceAccountName, ImagePullSecrets: imagePullSecrets, } v.resolvePodSpec(ctx, &ps.Spec.Template.Spec, opt) } // ResolvePodSpecable implements duckv1.PodSpecValidator func (v *Validator) ResolvePodSpecable(ctx context.Context, wp *duckv1.WithPod) { // Don't mess with things that are being deleted or already deleted or // status update. if isDeletedOrStatusUpdate(ctx, wp.DeletionTimestamp) { return } imagePullSecrets := make([]string, 0, len(wp.Spec.Template.Spec.ImagePullSecrets)) for _, s := range wp.Spec.Template.Spec.ImagePullSecrets { imagePullSecrets = append(imagePullSecrets, s.Name) } opt := k8schain.Options{ Namespace: getNamespace(ctx, wp.Namespace), ServiceAccountName: wp.Spec.Template.Spec.ServiceAccountName, ImagePullSecrets: imagePullSecrets, } v.resolvePodSpec(ctx, &wp.Spec.Template.Spec, opt) } // ResolvePod implements duckv1.PodValidator func (v *Validator) ResolvePod(ctx context.Context, p *duckv1.Pod) { // Don't mess with things that are being deleted or already deleted or // status update. if isDeletedOrStatusUpdate(ctx, p.DeletionTimestamp) { return } imagePullSecrets := make([]string, 0, len(p.Spec.ImagePullSecrets)) for _, s := range p.Spec.ImagePullSecrets { imagePullSecrets = append(imagePullSecrets, s.Name) } opt := k8schain.Options{ Namespace: getNamespace(ctx, p.Namespace), ServiceAccountName: p.Spec.ServiceAccountName, ImagePullSecrets: imagePullSecrets, } v.resolvePodSpec(ctx, &p.Spec, opt) } // ResolveCronJob implements duckv1.CronJobValidator func (v *Validator) ResolveCronJob(ctx context.Context, c *duckv1.CronJob) { // Don't mess with things that are being deleted or already deleted or // status update. if isDeletedOrStatusUpdate(ctx, c.DeletionTimestamp) { return } imagePullSecrets := make([]string, 0, len(c.Spec.JobTemplate.Spec.Template.Spec.ImagePullSecrets)) for _, s := range c.Spec.JobTemplate.Spec.Template.Spec.ImagePullSecrets { imagePullSecrets = append(imagePullSecrets, s.Name) } opt := k8schain.Options{ Namespace: getNamespace(ctx, c.Namespace), ServiceAccountName: c.Spec.JobTemplate.Spec.Template.Spec.ServiceAccountName, ImagePullSecrets: imagePullSecrets, } v.resolvePodSpec(ctx, &c.Spec.JobTemplate.Spec.Template.Spec, opt) } // For testing var remoteResolveDigest = ociremote.ResolveDigest func (v *Validator) resolvePodSpec(ctx context.Context, ps *corev1.PodSpec, opt k8schain.Options) { kc, err := registryauth.NewK8sKeychain(ctx, kubeclient.Get(ctx), opt) if err != nil { logging.FromContext(ctx).Warnf("Unable to build k8schain: %v", err) return } resolveContainers := func(cs []corev1.Container) { for i, c := range cs { ref, err := name.ParseReference(c.Image) if err != nil { logging.FromContext(ctx).Debugf("Unable to parse reference: %v", err) continue } // If we are in the context of a mutating webhook, then resolve the tag to a digest. switch { case apis.IsInCreate(ctx), apis.IsInUpdate(ctx): digest, err := remoteResolveDigest(ref, ociremote.WithRemoteOptions( remote.WithContext(ctx), remote.WithAuthFromKeychain(kc), )) if err != nil { logging.FromContext(ctx).Debugf("Unable to resolve digest %q: %v", ref.String(), err) continue } // Keep the original tag and append the digest if tagRef, ok := ref.(name.Tag); ok { cs[i].Image = fmt.Sprintf("%s@%s", tagRef.Name(), digest.DigestStr()) } else { cs[i].Image = digest.String() } } } } resolveEphemeralContainers := func(cs []corev1.EphemeralContainer) { for i, c := range cs { ref, err := name.ParseReference(c.Image) if err != nil { logging.FromContext(ctx).Debugf("Unable to parse reference: %v", err) continue } // If we are in the context of a mutating webhook, then resolve the tag to a digest. switch { case apis.IsInCreate(ctx), apis.IsInUpdate(ctx): digest, err := remoteResolveDigest(ref, ociremote.WithRemoteOptions( remote.WithContext(ctx), remote.WithAuthFromKeychain(kc), )) if err != nil { logging.FromContext(ctx).Debugf("Unable to resolve digest %q: %v", ref.String(), err) continue } // Keep the original tag and append the digest if tagRef, ok := ref.(name.Tag); ok { cs[i].Image = fmt.Sprintf("%s@%s", tagRef.Name(), digest.DigestStr()) } else { cs[i].Image = digest.String() } } } } resolveContainers(ps.InitContainers) resolveContainers(ps.Containers) resolveEphemeralContainers(ps.EphemeralContainers) } // getNamespace tries to extract the namespace from the HTTPRequest // if the namespace passed as argument is empty. This is a workaround // for a bug in k8s <= 1.24. func getNamespace(ctx context.Context, namespace string) string { if namespace == "" { r := apis.GetHTTPRequest(ctx) if r != nil && r.Body != nil { var review admissionv1.AdmissionReview if err := json.NewDecoder(r.Body).Decode(&review); err != nil { logging.FromContext(ctx).Errorf("could not decode body: %v", err) return "" } return review.Request.Namespace } } return namespace } // validateContainer will validate the container image, and any errors will use // field & index to craft the meaningful error message. // field is necessary because higher level resources come here from different // contexts and the container could be nested at different levels in the // resource // index is the number in the containers array from the said context. // // Returns any encountered errors, or nil in two cases: // All the matched policies were validated, or // no matching policies were found, but the PolicyControllerConfig has been // configured to allow images not matching any policies. func (v *Validator) validateContainerImage(ctx context.Context, containerImage string, namespace, field string, index int, kind, apiVersion string, labels map[string]string, kc authn.Keychain, ociRemoteOpts ...ociremote.Option) *apis.FieldError { ref, err := name.ParseReference(containerImage) if err != nil { return apis.ErrGeneric(err.Error(), "image").ViaFieldIndex(field, index) } config := config.FromContext(ctx) if config != nil { policies, err := config.ImagePolicyConfig.GetMatchingPolicies(ref.Name(), kind, apiVersion, labels) if err != nil { errorField := apis.ErrGeneric(err.Error(), "image").ViaFieldIndex(field, index) errorField.Details = containerImage return errorField } // If there is at least one policy that matches, that means it // has to be satisfied. if len(policies) > 0 { signatures, fieldErrors := validatePolicies(ctx, namespace, ref, policies, kc, ociRemoteOpts...) if len(signatures) != len(policies) { logging.FromContext(ctx).Warnf("Failed to validate at least one policy for %s wanted %d policies, only validated %d", ref.Name(), len(policies), len(signatures)) } else { logging.FromContext(ctx).Infof("Validated %d policies for image %s", len(signatures), containerImage) } return errorsToFieldErrors(containerImage, field, index, fieldErrors) } // Container matched no policies, so return based on the configured // NoMatchPolicy. return setNoMatchingPoliciesError(ctx, containerImage, field, index) } return nil } func errorsToFieldErrors(image, field string, index int, fieldErrors map[string][]error) (errs *apis.FieldError) { // Do we really want to add all the error details here? // Seems like we can just say which policy failed, so // doing that for now. // Split the errors and warnings to their own // error levels. hasWarnings := false hasErrors := false for failingPolicy, policyErrs := range fieldErrors { errDetails := image warnDetails := image for _, policyErr := range policyErrs { var fe *apis.FieldError if errors.As(policyErr, &fe) { if fe.Filter(apis.WarningLevel) != nil { warnDetails = warnDetails + " " + fe.Message hasWarnings = true } else { errDetails = errDetails + " " + fe.Message hasErrors = true } } else { // Just a regular error. errDetails = errDetails + " " + policyErr.Error() } } if hasWarnings { warnField := apis.ErrGeneric(fmt.Sprintf("failed policy: %s", failingPolicy), "image").ViaFieldIndex(field, index) warnField.Details = warnDetails errs = errs.Also(warnField).At(apis.WarningLevel) } if hasErrors { errorField := apis.ErrGeneric(fmt.Sprintf("failed policy: %s", failingPolicy), "image").ViaFieldIndex(field, index) errorField.Details = errDetails errs = errs.Also(errorField) } } return } // refOrFieldError parses the given image into a name.Reference, or returns // a properly constructed FieldError for a given field/index in the resource // spec. func refOrFieldError(image, field string, index int) *apis.FieldError { ref, err := name.ParseReference(image) if err != nil { return apis.ErrGeneric(err.Error(), "image").ViaFieldIndex(field, index) } if _, ok := ref.(name.Digest); !ok { return apis.ErrInvalidValue( fmt.Sprintf("%s must be an image digest", image), "image", ).ViaFieldIndex(field, index) } return nil } // configFileResult is used to communicate results from gofuncs that fetch // ConfigFiles for a given image. // Because this can be recursive (say, multi-arch image), returns a map where // key is the architecture of the container image. type configFileResult struct { ret map[string]*v1.ConfigFile errs []error } // getConfigs will fetch ConfigFile(s) for a given image. In case the image // is an index, we'll fetch the arch images recursively. func getConfigs(ctx context.Context, ref name.Reference, options ...remote.Option) (map[string]*v1.ConfigFile, []error) { descriptor, err := remote.Get(ref, options...) if err != nil { return nil, []error{fmt.Errorf("failed to get ref %s : %w", ref.String(), err)} } switch descriptor.MediaType { case types.OCIImageIndex, types.DockerManifestList: ii, err := descriptor.ImageIndex() if err != nil { return nil, []error{fmt.Errorf("getting ImageIndex for %s : %w", ref.String(), err)} } im, err := ii.IndexManifest() if err != nil { return nil, []error{fmt.Errorf("getting IndexManifest for %s : %w", ref.String(), err)} } wg := new(sync.WaitGroup) results := make(chan configFileResult, len(im.Manifests)) for _, manifest := range im.Manifests { manifest := manifest wg.Add(1) go func() { defer wg.Done() newRefString := ref.Context().Digest(manifest.Digest.String()).String() newRef, err := name.ParseReference(newRefString) if err != nil { results <- configFileResult{ret: nil, errs: []error{fmt.Errorf("failed to ParseReference for: %s: %w", newRefString, err)}} return } newRefConfigs, errs := getConfigs(ctx, newRef, options...) results <- configFileResult{ret: newRefConfigs, errs: errs} }() } errs := []error{} ret := make(map[string]*v1.ConfigFile, len(im.Manifests)) for i := 0; i < len(im.Manifests); i++ { select { case <-ctx.Done(): errs = append(errs, errors.New("context canceled")) case result, ok := <-results: if !ok { errs = append(errs, errors.New("channel closed before all results were gathered")) } else { if len(result.errs) != 0 { errs = append(errs, fmt.Errorf("failed to get a ConfigFile: %v", result.errs)) } else { for k, v := range result.ret { ret[k] = v } } } } } wg.Wait() if len(errs) > 0 { return nil, errs } return ret, nil case types.OCIManifestSchema1, types.DockerManifestSchema2: // This is an Image, so just return it. image, err := descriptor.Image() if err != nil { return nil, []error{fmt.Errorf("getting Image for %s: %w", ref.String(), err)} } cf, err := image.ConfigFile() if err != nil { return nil, []error{fmt.Errorf("getting ConfigFile for %s: %w", ref.String(), err)} } return map[string]*v1.ConfigFile{normalizeArchitecture(cf): cf}, nil default: return nil, []error{fmt.Errorf("unknown mime type for %s: %v", ref.String(), descriptor.MediaType)} } } // normalizeArchitecture normalizes the os/architecture/variant to: // {OS}/{Architecture}[/{Variant}] // // Some examples are: // linux/arm64 // linux/arm/v7 // linux/arm/v6 func normalizeArchitecture(cf *v1.ConfigFile) string { return v1.Platform{ Architecture: cf.Architecture, OS: cf.OS, OSVersion: cf.OSVersion, Variant: cf.Variant, }.String() } // checkOptsFromAuthority creates the necessary options for calling Cosign // verify functions (signatures and attestations). func checkOptsFromAuthority(ctx context.Context, authority webhookcip.Authority, remoteOpts ...ociremote.Option) (*cosign.CheckOpts, error) { // Get the policy controller configuration to check if OCI 1.1 is enabled cfg := policycontrollerconfig.FromContextOrDefaults(ctx) ret := &cosign.CheckOpts{ RegistryClientOpts: remoteOpts, NewBundleFormat: authority.SignatureFormat == "bundle", ExperimentalOCI11: cfg.EnableOCI11, } // Add in the identities for verification purposes if authority.Keyless != nil { for _, id := range authority.Keyless.Identities { ret.Identities = append(ret.Identities, cosign.Identity{ Issuer: id.Issuer, Subject: id.Subject, IssuerRegExp: id.IssuerRegExp, SubjectRegExp: id.SubjectRegExp}) } } if ret.NewBundleFormat { // The new bundle format is only supported for keyless authorities // and the trustRootRef must be set. if authority.Keyless == nil { // TODO: Support the new bundle format for non-keyless authorities return nil, fmt.Errorf("when using the new bundle format, the authority must be keyless") } trustRootRef := authority.Keyless.TrustRootRef if trustRootRef != "" { // Set up TrustedMaterial sigstoreKeys, err := sigstoreKeysFromContext(ctx, trustRootRef) if err != nil { return nil, fmt.Errorf("getting SigstoreKeys: %w", err) } sk, ok := sigstoreKeys.SigstoreKeys[trustRootRef] if !ok { return nil, fmt.Errorf("trustRootRef %s not found", trustRootRef) } ret.TrustedMaterial, err = root.NewTrustedRootFromProtobuf(sk) if err != nil { return nil, fmt.Errorf("failed to create trusted root from protobuf: %w", err) } } else { var err error ret.TrustedMaterial, err = pctuf.GetTrustedRoot(ctx) if err != nil { return nil, fmt.Errorf("failed to fetch trusted root: %w", err) } } if authority.Keyless.InsecureIgnoreSCT != nil && *authority.Keyless.InsecureIgnoreSCT { ret.IgnoreSCT = *authority.Keyless.InsecureIgnoreSCT } // Check for custom TSA tsa := authority.RFC3161Timestamp if tsa != nil { if tsa.TrustRootRef != authority.Keyless.TrustRootRef { return nil, fmt.Errorf("when using the new bundle format, the trustRootRef for the TSA must be the same as the trustRootRef for the Keyless authority") } ret.UseSignedTimestamps = true ret.IgnoreTlog = true } // Check for custom Rekor tlog := authority.CTLog if tlog != nil { if tlog.TrustRootRef != authority.Keyless.TrustRootRef { return nil, fmt.Errorf("when using the new bundle format, the trustRootRef for the TLog must be the same as the trustRootRef for the Keyless authority") } // Only require the TLog if we're not using signed timestamps if ret.UseSignedTimestamps { ret.IgnoreTlog = true } } return ret, nil } // If we're not using the new bundle verifier (TrustedMaterial), we need to assemble the other CheckOpts (Fulcio, Rekor, TSA, etc.) if authority.Keyless != nil { fulcioRoots, fulcioIntermediates, ctlogKeys, err := fulcioCertsFromAuthority(ctx, authority.Keyless) if err != nil { return nil, fmt.Errorf("getting Fulcio certs: %s: %w", authority.Name, err) } ret.RootCerts = fulcioRoots ret.IntermediateCerts = fulcioIntermediates ret.CTLogPubKeys = ctlogKeys if authority.Keyless.InsecureIgnoreSCT != nil && *authority.Keyless.InsecureIgnoreSCT { ret.IgnoreSCT = *authority.Keyless.InsecureIgnoreSCT } } rekorClient, rekorPubKeys, err := rekorClientAndKeysFromAuthority(ctx, authority) if err != nil { return nil, fmt.Errorf("getting Rekor public keys: %s: %w", authority.Name, err) } ret.RekorClient = rekorClient ret.RekorPubKeys = rekorPubKeys // Skip the TLog verification if we have no client or keys to validate // against. if ret.RekorClient == nil { if ret.RekorPubKeys != nil { // If there's keys however, use offline for verification. ret.Offline = true } else { // If there is not a rekor client definition then skip tlog verification. ret.IgnoreTlog = true } } if authority.RFC3161Timestamp != nil && authority.RFC3161Timestamp.TrustRootRef != "" { logging.FromContext(ctx).Debug("Using RFC3161Timestamp...") // TODO: By default, we disable any tlog verification when using the RFC3161Timestamp validation. // There are use cases when the validation is only handled by TSA, and there isn't any TLog involved. ret.IgnoreTlog = true ret.UseSignedTimestamps = true sigstoreKeys, err := sigstoreKeysFromContext(ctx, authority.RFC3161Timestamp.TrustRootRef) if err != nil { return nil, err } sk, ok := sigstoreKeys.SigstoreKeys[authority.RFC3161Timestamp.TrustRootRef] if !ok { return nil, fmt.Errorf("trustRootRef %s not found", authority.RFC3161Timestamp.TrustRootRef) } for _, timestampAuthority := range sk.TimestampAuthorities { leaves, intermediates, roots, err := splitPEMCertificateChain(config.SerializeCertChain(timestampAuthority.CertChain)) // TODO: this is less efficient than it could be if err != nil { return nil, fmt.Errorf("error splitting certificates: %w", err) } if len(leaves) > 1 { return nil, fmt.Errorf("certificate chain must contain at most one TSA certificate") } if len(leaves) == 1 { ret.TSACertificate = leaves[0] } ret.TSAIntermediateCertificates = intermediates ret.TSARootCertificates = roots } } return ret, nil } func sigstoreKeysFromContext(ctx context.Context, trustRootRef string) (*config.SigstoreKeysMap, error) { config := config.FromContext(ctx) if config == nil { // No config, can't fetch certificates, bail. return nil, fmt.Errorf("trustRootRef %s not found, config missing", trustRootRef) } if config.SigstoreKeysConfig == nil { // No config, can't fetch keys, bail. return nil, fmt.Errorf("trustRootRef %s not found, SigstoreKeys missing", trustRootRef) } return config.SigstoreKeysConfig, nil } // fulcioCertsFromAuthority gets the necessary Fulcio certificates, this is // rootPool and an optional intermediatePool. Additionally fetches the CTLog // public keys. // Preference is given to TrustRoot if specified, from which the certificates // are fetched and returned. If there's no TrustRoot, the certificates are // fetched from embedded or cached TUF root. func fulcioCertsFromAuthority(ctx context.Context, keylessRef *webhookcip.KeylessRef) (*x509.CertPool, *x509.CertPool, *cosign.TrustedTransparencyLogPubKeys, error) { // If this is not Keyless, there's no Fulcio, so just return if keylessRef.TrustRootRef == "" { roots, err := fulcioroots.Get() if err != nil { return nil, nil, nil, fmt.Errorf("failed to fetch Fulcio roots: %w", err) } intermediates, err := fulcioroots.GetIntermediates() if err != nil { return nil, nil, nil, fmt.Errorf("failed to fetch Fulcio intermediates: %w", err) } ctPubs, err := cosign.GetCTLogPubs(ctx) if err != nil { return nil, nil, nil, fmt.Errorf("failed to fetch CTLog public keys: %w", err) } return roots, intermediates, ctPubs, nil } // There's TrustRootRef, so fetch it trustRootRef := keylessRef.TrustRootRef sigstoreKeys, err := sigstoreKeysFromContext(ctx, trustRootRef) if err != nil { return nil, nil, nil, fmt.Errorf("getting SigstoreKeys: %w", err) } rootCertsPool := x509.NewCertPool() intermediateCertsPool := x509.NewCertPool() sk, ok := sigstoreKeys.SigstoreKeys[trustRootRef] if !ok { return nil, nil, nil, fmt.Errorf("trustRootRef %s not found", trustRootRef) } for _, ca := range sk.CertificateAuthorities { certs, err := cryptoutils.UnmarshalCertificatesFromPEM(config.SerializeCertChain(ca.CertChain)) // TODO: this is less efficient than it could be if err != nil { return nil, nil, nil, fmt.Errorf("error unmarshalling certificates: %w", err) } for _, cert := range certs { // root certificates are self-signed if bytes.Equal(cert.RawSubject, cert.RawIssuer) { rootCertsPool.AddCert(cert) } else { intermediateCertsPool.AddCert(cert) } } } ctlogKeys := &cosign.TrustedTransparencyLogPubKeys{ Keys: make(map[string]cosign.TransparencyLogPubKey, len(sk.Ctlogs)), } for i, ctlog := range sk.Ctlogs { pk, err := cryptoutils.UnmarshalPEMToPublicKey(config.SerializePublicKey(ctlog.PublicKey)) // TODO: this is less efficient than it could be if err != nil { return nil, nil, nil, fmt.Errorf("unmarshaling public key %d failed: %w", i, err) } ctlogKeys.Keys[string(ctlog.LogId.KeyId)] = cosign.TransparencyLogPubKey{ PubKey: pk, Status: tuf.Active, } } if len(ctlogKeys.Keys) == 0 { // if keys are empty just return a nil map to make easier for the caller // to see if it's empty. ctlogKeys = nil } return rootCertsPool, intermediateCertsPool, ctlogKeys, nil } // rekorClientAndKeysFromAuthority creates a Rekor client that should be used // and public keys to go with it. // Note that if Rekor is not specified, it's not an error and nil will be // returned for it. // Preference is given to TrustRoot if specified, from which the URL and public // keys are fetched and returned. If there's no TrustRoot but a URL, then // a Rekor client is returned and the keys from the embedded or cached TUF root. func rekorClientAndKeysFromAuthority(ctx context.Context, authority webhookcip.Authority) (*client.Rekor, *cosign.TrustedTransparencyLogPubKeys, error) { // In keyless, if no TrustRoot was defined and CTLog is nil, then default to rekor pub keys as done in cosign if authority.Keyless != nil && authority.Keyless.TrustRootRef == "" && authority.CTLog == nil { rekorPubKeys, err := cosign.GetRekorPubs(ctx) if err != nil { logging.FromContext(ctx).Errorf("failed getting rekor public keys: %v", err) return nil, nil, fmt.Errorf("getting Rekor public keys: %w", err) } return nil, rekorPubKeys, nil } tlog := authority.CTLog if tlog == nil { return nil, nil, nil } if tlog.TrustRootRef != "" { trustRootRef := tlog.TrustRootRef rekorPubKeys, rekorURL, err := rekorKeysFromTrustRef(ctx, trustRootRef) if err != nil { return nil, nil, fmt.Errorf("fetching keys for trustRootRef: %w", err) } if rekorURL == "" && tlog.URL != nil { // Pull this from the tlog entry in this case. rekorURL = tlog.URL.String() } rekorClient, err := rekor.GetRekorClient(rekorURL) if err != nil { logging.FromContext(ctx).Errorf("failed creating rekor client: %v", err) return nil, nil, fmt.Errorf("creating Rekor client: %w", err) } return rekorClient, rekorPubKeys, nil } // No TrustRoot, so see if there's one specified in the authority and if // not just return that no Rekor is to be used. if tlog.URL == nil { return nil, nil, nil } rekorClient, err := rekor.GetRekorClient(tlog.URL.String()) if err != nil { logging.FromContext(ctx).Errorf("failed creating rekor client: %v", err) return nil, nil, fmt.Errorf("creating Rekor client: %w", err) } rekorPubKeys, err := cosign.GetRekorPubs(ctx) if err != nil { logging.FromContext(ctx).Errorf("failed getting rekor public keys: %v", err) return nil, nil, fmt.Errorf("getting Rekor public keys: %w", err) } return rekorClient, rekorPubKeys, nil } func rekorKeysFromTrustRef(ctx context.Context, trustRootRef string) (*cosign.TrustedTransparencyLogPubKeys, string, error) { sigstoreKeys, err := sigstoreKeysFromContext(ctx, trustRootRef) if err != nil { return nil, "", fmt.Errorf("getting SigstoreKeys: %w", err) } if sk, ok := sigstoreKeys.SigstoreKeys[trustRootRef]; ok { retKeys := &cosign.TrustedTransparencyLogPubKeys{ Keys: make(map[string]cosign.TransparencyLogPubKey, len(sk.Tlogs)), } rekorURL := "" for i, tlog := range sk.Tlogs { pk, err := cryptoutils.UnmarshalPEMToPublicKey(config.SerializePublicKey(tlog.PublicKey)) if err != nil { return nil, "", fmt.Errorf("unmarshaling public key %d failed: %w", i, err) } // This needs to be ecdsa instead of crypto.PublicKey // https://github.com/sigstore/cosign/issues/2540 pkecdsa, ok := pk.(*ecdsa.PublicKey) if !ok { return nil, "", fmt.Errorf("public key %d is not ecdsa.PublicKey", i) } retKeys.Keys[string(tlog.LogId.KeyId)] = cosign.TransparencyLogPubKey{ PubKey: pkecdsa, Status: tuf.Active, } rekorURL = tlog.BaseUrl } return retKeys, rekorURL, nil } return nil, "", fmt.Errorf("trustRootRef %s not found", trustRootRef) } // splitPEMCertificateChain returns a list of leaf (non-CA) certificates, a certificate pool for // intermediate CA certificates, and a certificate pool for root CA certificates func splitPEMCertificateChain(pem []byte) (leaves, intermediates, roots []*x509.Certificate, err error) { certs, err := cryptoutils.UnmarshalCertificatesFromPEM(pem) if err != nil { return nil, nil, nil, err } for _, cert := range certs { if !cert.IsCA { leaves = append(leaves, cert) } else { // root certificates are self-signed if bytes.Equal(cert.RawSubject, cert.RawIssuer) { roots = append(roots, cert) } else { intermediates = append(intermediates, cert) } } } return leaves, intermediates, roots, nil } ================================================ FILE: pkg/webhook/validator_result.go ================================================ // // 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. package webhook import ( v1 "github.com/google/go-containerregistry/pkg/v1" ) // PolicyResult is the result of a successful ValidatePolicy call. // These are meant to be consumed by a higher level Policy engine that // can reason about validated results. The 'first' level pass will verify // signatures and attestations, and make the results then available for // a policy that can be used to gate a passing of a ClusterImagePolicy. // Some examples are, at least 'vulnerability' has to have been done // and the scan must have been attested by a particular entity (sujbect/issuer) // or a particular key. // Other examples are N-of-M must be satisfied and so forth. // We do not expose the low level details of signatures / attestations here // since they have already been validated as per the Authority configuration // and optionally by the Attestations which contain a particular policy that // can be used to validate the Attestations (say vulnerability scanner must not // have any High sev issues). type PolicyResult struct { // AuthorityMatches will have an entry for each successful Authority check // on it. Key in the map is the Attestation.Name AuthorityMatches map[string]AuthorityMatch `json:"authorityMatches,omitempty"` // Config contains the Config for each of the normalized os/architectures // where key to the map is the {OS}/{Architecture}[/{Variant}] // // Some examples are: // linux/arm64 // linux/arm/v7 // linux/arm/v6 // // This field is only available for evaluation if // CIP.Spec.Policy.FetchConfigFile is set to true. Config map[string]*v1.ConfigFile `json:"config,omitempty"` // Spec contains the Spec for the resource that was evaluated. Note // that because this is resource specific, so you can use MatchResource // to filter to only specific resource to get only the Specs you want. // // This field is only available for evaluation if // CIP.Spec.Policy.IncludeSpec is set to true. Spec interface{} `json:"spec,omitempty"` // ObjectMeta contains the ObjectMeta for the resource that was evaluated. // // This field is only available for evaluation if // CIP.Spec.Policy.IncludeObjectMeta is set to true. ObjectMeta interface{} `json:"metadata,omitempty"` // TypeMeta contains the TypeMeta for the resource that was evaluated. // // This field is only available for evaluation if // CIP.Spec.Policy.IncludeTypeMeta is set to true. TypeMeta interface{} `json:"typemeta,omitempty"` } // AuthorityMatch returns either Signatures (if there are no Attestations // specified), or Attestations if there are Attestations specified. type AuthorityMatch struct { // All of the matching signatures for this authority // Wonder if for consistency this should also have the matching // attestations name, aka, make this into a map. Signatures []PolicySignature `json:"signatures,omitempty"` // Mapping from attestation name to all of verified attestations Attestations map[string][]PolicyAttestation `json:"attestations,omitempty"` // Static indicates whether this authority matched due to static // e.g. static: { action: pass } Static bool `json:"static,omitempty"` } // PolicySignature contains a normalized result of a validated signature, where // signature could be a signature on the Image (.sig) or on an Attestation // (.att). type PolicySignature struct { // A unique identifier describing this signature. // This is typically the hash of this signature's OCI layer for images. ID string `json:"id,omitempty"` // Subject that was found to match on the Cert. Subject string `json:"subject,omitempty"` // Issure that was found to match on the Cert. Issuer string `json:"issuer,omitempty"` // GithubExtensions holds the Github-related OID extensions. // See also: https://github.com/sigstore/fulcio/blob/main/docs/oid-info.md GithubExtensions `json:",inline"` } // PolicyAttestation contains a normalized result of a validated attestation, // which consists of the PolicySignature part, and some additional attestation // specific fields. type PolicyAttestation struct { PolicySignature `json:",inline"` // PredicateType is the in-toto predicate type of this attestation. PredicateType string `json:"predicateType,omitempty"` // Payload is the bytes of the in-toto statement's predicate payload. // This is included for the benefit of the caller of ValidatePolicy, and is // not intended for consumption in the ClusterImagePolicy's outer policy // block. Payload []byte `json:"-"` // Digest of the attestation Digest string `json:"digest,omitempty"` } // GithubExtensions holds the Github-related OID extensions. // See also: https://github.com/sigstore/fulcio/blob/main/docs/oid-info.md // NOTE: these field correlate with the names given in the cosign // CertExtensionMap and must be prefixed with "github" to avoid ambiguity. type GithubExtensions struct { // OID: 1.3.6.1.4.1.57264.1.2 WorkflowTrigger string `json:"githubWorkflowTrigger,omitempty"` // OID: 1.3.6.1.4.1.57264.1.3 WorkflowSHA string `json:"githubWorkflowSha,omitempty"` // OID: 1.3.6.1.4.1.57264.1.4 WorkflowName string `json:"githubWorkflowName,omitempty"` // OID: 1.3.6.1.4.1.57264.1.5 WorkflowRepo string `json:"githubWorkflowRepo,omitempty"` // OID: 1.3.6.1.4.1.57264.1.6 WorkflowRef string `json:"githubWorkflowRef,omitempty"` } ================================================ FILE: pkg/webhook/validator_test.go ================================================ // // Copyright 2021 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. package webhook import ( "bytes" "context" "crypto" "crypto/ecdsa" "crypto/x509" "encoding/base64" "encoding/json" "errors" "fmt" "io" "net/http" "net/http/httptest" "os" "strings" "testing" "time" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/google/go-containerregistry/pkg/authn/k8schain" "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" v1types "github.com/google/go-containerregistry/pkg/v1/types" "github.com/sigstore/cosign/v3/pkg/cosign" "github.com/sigstore/cosign/v3/pkg/cosign/bundle" "github.com/sigstore/cosign/v3/pkg/oci" "github.com/sigstore/cosign/v3/pkg/oci/remote" "github.com/sigstore/cosign/v3/pkg/oci/static" "github.com/sigstore/policy-controller/pkg/apis/config" policyduckv1beta1 "github.com/sigstore/policy-controller/pkg/apis/duck/v1beta1" "github.com/sigstore/policy-controller/pkg/apis/policy/v1alpha1" "github.com/sigstore/policy-controller/pkg/apis/signaturealgo" policycontrollerconfig "github.com/sigstore/policy-controller/pkg/config" webhookcip "github.com/sigstore/policy-controller/pkg/webhook/clusterimagepolicy" pbcommon "github.com/sigstore/protobuf-specs/gen/pb-go/common/v1" "github.com/sigstore/sigstore-go/pkg/root" "github.com/sigstore/sigstore/pkg/cryptoutils" "github.com/sigstore/sigstore/pkg/fulcioroots" "github.com/sigstore/sigstore/pkg/tuf" admissionv1 "k8s.io/api/admission/v1" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "knative.dev/pkg/apis" duckv1 "knative.dev/pkg/apis/duck/v1" kubeclient "knative.dev/pkg/client/injection/kube/client" fakekube "knative.dev/pkg/client/injection/kube/client/fake" "knative.dev/pkg/ptr" rtesting "knative.dev/pkg/reconciler/testing" "knative.dev/pkg/system" ) const ( fulcioRootCert = "-----BEGIN CERTIFICATE-----\nMIICNzCCAd2gAwIBAgITPLBoBQhl1hqFND9S+SGWbfzaRTAKBggqhkjOPQQDAjBo\nMQswCQYDVQQGEwJVSzESMBAGA1UECBMJV2lsdHNoaXJlMRMwEQYDVQQHEwpDaGlw\ncGVuaGFtMQ8wDQYDVQQKEwZSZWRIYXQxDDAKBgNVBAsTA0NUTzERMA8GA1UEAxMI\ndGVzdGNlcnQwHhcNMjEwMzEyMjMyNDQ5WhcNMzEwMjI4MjMyNDQ5WjBoMQswCQYD\nVQQGEwJVSzESMBAGA1UECBMJV2lsdHNoaXJlMRMwEQYDVQQHEwpDaGlwcGVuaGFt\nMQ8wDQYDVQQKEwZSZWRIYXQxDDAKBgNVBAsTA0NUTzERMA8GA1UEAxMIdGVzdGNl\ncnQwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQRn+Alyof6xP3GQClSwgV0NFuY\nYEwmKP/WLWr/LwB6LUYzt5v49RlqG83KuaJSpeOj7G7MVABdpIZYWwqAiZV3o2Yw\nZDAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB/wIBATAdBgNVHQ4EFgQU\nT8Jwm6JuVb0dsiuHUROiHOOVHVkwHwYDVR0jBBgwFoAUT8Jwm6JuVb0dsiuHUROi\nHOOVHVkwCgYIKoZIzj0EAwIDSAAwRQIhAJkNZmP6sKA+8EebRXFkBa9DPjacBpTc\nOljJotvKidRhAiAuNrIazKEw2G4dw8x1z6EYk9G+7fJP5m93bjm/JfMBtA==\n-----END CERTIFICATE-----" rekorResponse = "bad response" // Random public key (cosign generate-key-pair) 2022-03-18 authorityKeyCosignPubString = `-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENAyijLvRu5QpCPp2uOj8C79ZW1VJ SID/4H61ZiRzN4nqONzp+ZF22qQTk3MFO3D0/ZKmWHAosIf2pf2GHH7myA== -----END PUBLIC KEY-----` certChain = `-----BEGIN CERTIFICATE----- MIIBzDCCAXKgAwIBAgIUfyGKDoFa7y6s/W1p1CiTmBRs1eAwCgYIKoZIzj0EAwIw MDEOMAwGA1UEChMFbG9jYWwxHjAcBgNVBAMTFVRlc3QgVFNBIEludGVybWVkaWF0 ZTAeFw0yMjExMDkyMDMxMzRaFw0zMTExMDkyMDM0MzRaMDAxDjAMBgNVBAoTBWxv Y2FsMR4wHAYDVQQDExVUZXN0IFRTQSBUaW1lc3RhbXBpbmcwWTATBgcqhkjOPQIB BggqhkjOPQMBBwNCAAR3KcDy9jwARX0rDvyr+MGGkG3n1OA0MU5+ZiDmgusFyk6U 6bovKWVMfD8J8NTcJZE0RaYJr8/dE9kgcIIXlhMwo2owaDAOBgNVHQ8BAf8EBAMC B4AwHQYDVR0OBBYEFHNn5R3b3MtUdSNrFO49Q6XDVSnkMB8GA1UdIwQYMBaAFNLS 6gno7Om++Qt5zIa+H9o0HiT2MBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMAoGCCqG SM49BAMCA0gAMEUCIQCF0olohnvdUq6T7/wPk19Z5aQP/yxRTjCWYuhn/TCyHgIg azV3air4GRZbN9bdYtcQ7JUAKq89GOhtFfl6kcoVUvU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIB0jCCAXigAwIBAgIUXpBmYJFFaGW3cC8p6b/DHr1i8IowCgYIKoZIzj0EAwIw KDEOMAwGA1UEChMFbG9jYWwxFjAUBgNVBAMTDVRlc3QgVFNBIFJvb3QwHhcNMjIx MTA5MjAyOTM0WhcNMzIxMTA5MjAzNDM0WjAwMQ4wDAYDVQQKEwVsb2NhbDEeMBwG A1UEAxMVVGVzdCBUU0EgSW50ZXJtZWRpYXRlMFkwEwYHKoZIzj0CAQYIKoZIzj0D AQcDQgAEKDPDRIwDS1ZCymub6yanCG5ma0qDjLpNonDvooSkRHEgU0TNibeJn6M+ 5W608hCw8nwuucMbXQ41kNeuBeevyqN4MHYwDgYDVR0PAQH/BAQDAgEGMBMGA1Ud JQQMMAoGCCsGAQUFBwMIMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNLS6gno 7Om++Qt5zIa+H9o0HiT2MB8GA1UdIwQYMBaAFB1nvXpNK7AuQlbJ+ya6nPSqWi+T MAoGCCqGSM49BAMCA0gAMEUCIGiwqCI29w7C4V8TltCsi728s5DtklCPySDASUSu a5y5AiEA40Ifdlwf7Uj8q8NSD6Z4g/0js0tGNdLSUJ1do/WoN0s= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIBlDCCATqgAwIBAgIUYZx9sS14En7SuHDOJJP4IPopMjUwCgYIKoZIzj0EAwIw KDEOMAwGA1UEChMFbG9jYWwxFjAUBgNVBAMTDVRlc3QgVFNBIFJvb3QwHhcNMjIx MTA5MjAyOTM0WhcNMzIxMTA5MjAzNDM0WjAoMQ4wDAYDVQQKEwVsb2NhbDEWMBQG A1UEAxMNVGVzdCBUU0EgUm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAbB B0SU8G75hVIUphChA4nfOwNWP347TjScIdsEPrKVn+/Y1HmmLHJDjSfn+xhEFoEk 7jqgrqon48i4xbo7xAujQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD AQH/MB0GA1UdDgQWBBQdZ716TSuwLkJWyfsmupz0qlovkzAKBggqhkjOPQQDAgNI ADBFAiBe5P56foqmFcZAVpEeAOFZrAlEiq05CCpMNYh5EjLvmAIhAKNF6xIV5uFd pSTJsAwzjW78CKQm7qol0uPmPPu6mNaw -----END CERTIFICATE----- ` rekorPublicKey = `-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE7D2WvgqSzs9jpdJsOJ5Nl6xg8JXm Nmo7M3bN7+dQddw9Ibc2R3SV8tzBZw0rST8FKcn4apJepcKM4qUpYUeNfw== -----END PUBLIC KEY----- ` // This is the Rekor LogID constructed from above public key. rekorLogID = "0bac0fddd0c15fbc46f8b1bf51c2b57676a9f262294fe13417d85602e73f392a" ctfePublicKey = `-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEJvCJi707fv5tMJ1U2TVMZ+uO4dKG aEcvjlCkgBCKXbrkumZV0m0dSlK1V1gxEiyQ8y6hk1MxJNe2AZrZUt7a4w== -----END PUBLIC KEY----- ` // This is the LogID for above PublicKey ctfeLogID = "39d1c085f7d5f3fe7a0de9e52a3ead14186891e52a9269d90de7990a30b55083" ) func TestValidatePodSpec(t *testing.T) { tag := name.MustParseReference("gcr.io/distroless/static:nonroot") // Resolved via crane digest on 2021/09/25 digest := name.MustParseReference("gcr.io/distroless/static:nonroot@sha256:be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4") // Resolved via crane digest on 2022/09/29 digestNewer := name.MustParseReference("gcr.io/distroless/static:nonroot@sha256:2a9e2b4fa771d31fe3346a873be845bfc2159695b9f90ca08e950497006ccc2e") ctx, _ := rtesting.SetupFakeContext(t) // Non-existent URL for testing complete failure badURL := apis.HTTP("http://example.com/") fulcioURL, err := apis.ParseURL("https://fulcio.sigstore.dev") if err != nil { t.Fatalf("Failed to parse fake Fulcio URL") } rekorServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { rw.Write([]byte(rekorResponse)) })) t.Cleanup(rekorServer.Close) rekorURL, err := apis.ParseURL(rekorServer.URL) if err != nil { t.Fatalf("Failed to parse fake Rekor URL") } var authorityKeyCosignPub *ecdsa.PublicKey pems := parsePems([]byte(authorityKeyCosignPubString)) if len(pems) > 0 { key, _ := x509.ParsePKIXPublicKey(pems[0].Bytes) authorityKeyCosignPub = key.(*ecdsa.PublicKey) } else { t.Errorf("Error parsing authority key from string") } kc := fakekube.Get(ctx) // Setup service acc and fakeSignaturePullSecrets for "default" and "cosign-system" namespace for _, ns := range []string{"default", system.Namespace()} { kc.CoreV1().ServiceAccounts(ns).Create(ctx, &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: "default", }, }, metav1.CreateOptions{}) kc.CoreV1().Secrets(ns).Create(ctx, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: "fakeSignaturePullSecrets", }, Data: map[string][]byte{ "dockerconfigjson": []byte(`{"auths":{"https://index.docker.io/v1/":{"username":"username","password":"password","auth":"dXNlcm5hbWU6cGFzc3dvcmQ="}}`), }, }, metav1.CreateOptions{}) } v := NewValidator(ctx) cvs := cosignVerifySignatures defer func() { cosignVerifySignatures = cvs }() // Let's just say that everything is verified. pass := func(_ context.Context, _ name.Reference, _ *cosign.CheckOpts) (checkedSignatures []oci.Signature, bundleVerified bool, err error) { sig, err := static.NewSignature(nil, "") if err != nil { return nil, false, err } return []oci.Signature{sig}, true, nil } // Let's just say that everything is not verified. fail := func(_ context.Context, _ name.Reference, _ *cosign.CheckOpts) (checkedSignatures []oci.Signature, bundleVerified bool, err error) { return nil, false, errors.New("bad signature") } // Let's say it is verified if it is the expected Public Key authorityPublicKeyCVS := func(ctx context.Context, signedImgRef name.Reference, co *cosign.CheckOpts) (checkedSignatures []oci.Signature, bundleVerified bool, err error) { actualPublicKey, _ := co.SigVerifier.PublicKey() actualECDSAPubkey := actualPublicKey.(*ecdsa.PublicKey) actualPubKey, err := actualECDSAPubkey.ECDH() if err != nil { return nil, false, errors.New("failed to get edch pub key") } authorityKeyPubKey, err := authorityKeyCosignPub.ECDH() if err != nil { return nil, false, errors.New("failed to get edch pub key") } if bytes.Equal(actualPubKey.Bytes(), authorityKeyPubKey.Bytes()) { return pass(ctx, signedImgRef, co) } return fail(ctx, signedImgRef, co) } tests := []struct { name string ps *corev1.PodSpec want *apis.FieldError cvs func(context.Context, name.Reference, *cosign.CheckOpts) ([]oci.Signature, bool, error) customContext context.Context }{{ name: "simple, no error", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, cvs: pass, customContext: config.ToContext(context.Background(), &config.Config{ ImagePolicyConfig: &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{ "cluster-image-policy": { Images: []v1alpha1.ImagePattern{{ Glob: "gcr.io/*/*", }}, Authorities: []webhookcip.Authority{ { Key: &webhookcip.KeyRef{ Data: authorityKeyCosignPubString, PublicKeys: []crypto.PublicKey{authorityKeyCosignPub}, HashAlgorithm: signaturealgo.DefaultSignatureAlgorithm, HashAlgorithmCode: crypto.SHA256, }, }, }, }, }, }, }, ), }, { name: "bad reference", ps: &corev1.PodSpec{ Containers: []corev1.Container{{ Name: "user-container", Image: "in@valid", }}, }, want: &apis.FieldError{ Message: `could not parse reference: in@valid`, Paths: []string{"containers[0].image"}, }, cvs: fail, }, { name: "not digest", ps: &corev1.PodSpec{ Containers: []corev1.Container{{ Name: "user-container", Image: tag.String(), }}, }, want: &apis.FieldError{ Message: `invalid value: gcr.io/distroless/static:nonroot must be an image digest`, Paths: []string{"containers[0].image"}, }, cvs: fail, }, { name: "simple, no error, authority key", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, customContext: config.ToContext(context.Background(), &config.Config{ ImagePolicyConfig: &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{ "cluster-image-policy": { Images: []v1alpha1.ImagePattern{{ Glob: "gcr.io/*/*", }}, Authorities: []webhookcip.Authority{ { Key: &webhookcip.KeyRef{ Data: authorityKeyCosignPubString, PublicKeys: []crypto.PublicKey{authorityKeyCosignPub}, HashAlgorithm: signaturealgo.DefaultSignatureAlgorithm, HashAlgorithmCode: crypto.SHA256, }, }, }, }, }, }, }, ), cvs: authorityPublicKeyCVS, }, { name: "simple, error, authority keyless, bad fulcio", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, customContext: config.ToContext(context.Background(), &config.Config{ ImagePolicyConfig: &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{ "cluster-image-policy-keyless": { Images: []v1alpha1.ImagePattern{{ Glob: "gcr.io/*/*", }}, Authorities: []webhookcip.Authority{ { Keyless: &webhookcip.KeylessRef{ URL: badURL, }, }, }, }, }, }, }, ), want: func() *apis.FieldError { var errs *apis.FieldError fe := apis.ErrGeneric("failed policy: cluster-image-policy-keyless", "image").ViaFieldIndex("containers", 0) fe.Details = fmt.Sprintf("%s %s", digest.String(), `signature keyless validation failed for authority for gcr.io/distroless/static@sha256:be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4: bad signature`) errs = errs.Also(fe) fe2 := apis.ErrGeneric("failed policy: cluster-image-policy-keyless", "image").ViaFieldIndex("initContainers", 0) fe2.Details = fe.Details errs = errs.Also(fe2) return errs }(), cvs: fail, }, { name: "simple, error, authority keyless, good fulcio, no rekor", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, customContext: config.ToContext(context.Background(), &config.Config{ ImagePolicyConfig: &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{ "cluster-image-policy-keyless": { Images: []v1alpha1.ImagePattern{{ Glob: "gcr.io/*/*", }}, Authorities: []webhookcip.Authority{ { Keyless: &webhookcip.KeylessRef{ URL: fulcioURL, }, }, }, }, }, }, }, ), want: func() *apis.FieldError { var errs *apis.FieldError fe := apis.ErrGeneric("failed policy: cluster-image-policy-keyless", "image").ViaFieldIndex("initContainers", 0) fe.Details = fmt.Sprintf("%s signature keyless validation failed for authority for %s: bad signature", digest.String(), digest.Name()) errs = errs.Also(fe) fe2 := apis.ErrGeneric("failed policy: cluster-image-policy-keyless", "image").ViaFieldIndex("containers", 0) fe2.Details = fmt.Sprintf("%s signature keyless validation failed for authority for %s: bad signature", digest.String(), digest.Name()) errs = errs.Also(fe2) return errs }(), cvs: fail, }, { name: "simple, authority keyless checks out, good fulcio, bad cip policy", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, customContext: config.ToContext(context.Background(), &config.Config{ ImagePolicyConfig: &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{ "cluster-image-policy-keyless-bad-cip": { Images: []v1alpha1.ImagePattern{{ Glob: "gcr.io/*/*", }}, Authorities: []webhookcip.Authority{ { Keyless: &webhookcip.KeylessRef{ URL: fulcioURL, }, }, }, Policy: &webhookcip.AttestationPolicy{ Name: "invalid json policy", Type: "cue", Data: `{"wontgo`, }, }, }, }, }, ), want: func() *apis.FieldError { var errs *apis.FieldError fe := apis.ErrGeneric("failed policy: cluster-image-policy-keyless-bad-cip", "image").ViaFieldIndex("initContainers", 0) fe.Details = fmt.Sprintf("%s failed evaluating cue policy for ClusterImagePolicy: failed to compile the cue policy with error: string literal not terminated", digest.String()) errs = errs.Also(fe) fe2 := apis.ErrGeneric("failed policy: cluster-image-policy-keyless-bad-cip", "image").ViaFieldIndex("containers", 0) fe2.Details = fmt.Sprintf("%s failed evaluating cue policy for ClusterImagePolicy: failed to compile the cue policy with error: string literal not terminated", digest.String()) errs = errs.Also(fe2) return errs }(), cvs: pass, }, { name: "simple, no error, authority keyless, good fulcio", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, customContext: config.ToContext(context.Background(), &config.Config{ ImagePolicyConfig: &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{ "cluster-image-policy-keyless": { Images: []v1alpha1.ImagePattern{{ Glob: "gcr.io/*/*", }}, Authorities: []webhookcip.Authority{ { Keyless: &webhookcip.KeylessRef{ URL: fulcioURL, }, }, }, }, }, }, }, ), cvs: pass, }, { name: "simple, error, authority keyless, good fulcio, bad rekor", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, customContext: config.ToContext(context.Background(), &config.Config{ ImagePolicyConfig: &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{ "cluster-image-policy-keyless": { Images: []v1alpha1.ImagePattern{{ Glob: "gcr.io/*/*", }}, Authorities: []webhookcip.Authority{ { Keyless: &webhookcip.KeylessRef{ URL: fulcioURL, }, CTLog: &v1alpha1.TLog{ URL: rekorURL, }, }, }, }, }, }, }, ), want: func() *apis.FieldError { var errs *apis.FieldError fe := apis.ErrGeneric("failed policy: cluster-image-policy-keyless", "image").ViaFieldIndex("initContainers", 0) fe.Details = fmt.Sprintf("%s signature keyless validation failed for authority for %s: bad signature", digest.String(), digest.Name()) errs = errs.Also(fe) fe2 := apis.ErrGeneric("failed policy: cluster-image-policy-keyless", "image").ViaFieldIndex("containers", 0) fe2.Details = fmt.Sprintf("%s signature keyless validation failed for authority for %s: bad signature", digest.String(), digest.Name()) errs = errs.Also(fe2) return errs }(), cvs: fail, }, { name: "simple with 2 containers, error, authority keyless, good fulcio, bad rekor", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }, { Name: "user-container-2", Image: digestNewer.String(), }}, }, customContext: config.ToContext(context.Background(), &config.Config{ ImagePolicyConfig: &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{ "cluster-image-policy-keyless": { Images: []v1alpha1.ImagePattern{{ Glob: "gcr.io/*/*", }}, Authorities: []webhookcip.Authority{ { Keyless: &webhookcip.KeylessRef{ URL: fulcioURL, }, CTLog: &v1alpha1.TLog{ URL: rekorURL, }, }, }, }, }, }, }, ), want: func() *apis.FieldError { var errs *apis.FieldError fe := apis.ErrGeneric("failed policy: cluster-image-policy-keyless", "image").ViaFieldIndex("initContainers", 0) fe.Details = fmt.Sprintf("%s signature keyless validation failed for authority for %s: bad signature", digest.String(), digest.Name()) errs = errs.Also(fe) fe2 := apis.ErrGeneric("failed policy: cluster-image-policy-keyless", "image").ViaFieldIndex("containers", 0) fe2.Details = fmt.Sprintf("%s signature keyless validation failed for authority for %s: bad signature", digest.String(), digest.Name()) errs = errs.Also(fe2) fe3 := apis.ErrGeneric("failed policy: cluster-image-policy-keyless", "image").ViaFieldIndex("containers", 1) fe3.Details = fmt.Sprintf("%s signature keyless validation failed for authority for %s: bad signature", digestNewer.String(), digestNewer.Name()) errs = errs.Also(fe3) return errs }(), cvs: fail, }, { name: "simple, no error, authority source signaturePullSecrets, non existing secret", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, customContext: config.ToContext(ctx, &config.Config{ ImagePolicyConfig: &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{ "cluster-image-policy": { Images: []v1alpha1.ImagePattern{{ Glob: "gcr.io/*/*", }}, Authorities: []webhookcip.Authority{ { Key: &webhookcip.KeyRef{ Data: authorityKeyCosignPubString, PublicKeys: []crypto.PublicKey{authorityKeyCosignPub}, HashAlgorithmCode: crypto.SHA256, HashAlgorithm: signaturealgo.DefaultSignatureAlgorithm, }, Sources: []v1alpha1.Source{{ OCI: "example.com/alternative/signature", SignaturePullSecrets: []corev1.LocalObjectReference{{ Name: "non-existing-secret", }}, }}, }, }, }, }, }, }, ), cvs: pass, }, { name: "simple, no error, authority source signaturePullSecrets, valid secret", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }, { Name: "user-container-2", Image: digestNewer.String(), }}, }, customContext: config.ToContext(ctx, &config.Config{ ImagePolicyConfig: &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{ "cluster-image-policy": { Images: []v1alpha1.ImagePattern{{ Glob: "gcr.io/*/*", }}, Authorities: []webhookcip.Authority{ { Key: &webhookcip.KeyRef{ Data: authorityKeyCosignPubString, PublicKeys: []crypto.PublicKey{authorityKeyCosignPub}, HashAlgorithm: signaturealgo.DefaultSignatureAlgorithm, HashAlgorithmCode: crypto.SHA256, }, Sources: []v1alpha1.Source{{ OCI: "example.com/alternative/signature", SignaturePullSecrets: []corev1.LocalObjectReference{{ Name: "fakeSignaturePullSecrets", }}, }}, }, }, }, }, }, }, ), cvs: authorityPublicKeyCVS, }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { for _, mode := range []string{"", "enforce", "warn"} { cosignVerifySignatures = test.cvs testContext := context.Background() // By default we want errors. However, iff the mode above is // warn, and we're using a custom context and therefore // triggering the CIP.mode twiddling below, check for warnings. wantWarn := false if test.customContext != nil { if mode == "warn" { wantWarn = true } // If we are testing with custom context, loop through // all the modes here. It's a bit silly that we spin through // all the tests 3 times, but for now this is better than // duplicating all the CIPs with just different modes. testContext = test.customContext // Twiddle the mode for tests. cfg := config.FromContext(testContext) newPolicies := make(map[string]webhookcip.ClusterImagePolicy, len(cfg.ImagePolicyConfig.Policies)) for k, v := range cfg.ImagePolicyConfig.Policies { v.Mode = mode newPolicies[k] = v } cfg.ImagePolicyConfig.Policies = newPolicies config.ToContext(testContext, cfg) } testContext = context.WithValue(testContext, kubeclient.Key{}, kc) // Check the core mechanics got := v.validatePodSpec(testContext, system.Namespace(), "Pod", "v1", map[string]string{}, test.ps, k8schain.Options{}) if (got != nil) != (test.want != nil) { t.Errorf("validatePodSpec() = %v, wanted %v", got, test.want) } else if got != nil && got.Error() != test.want.Error() { t.Errorf("validatePodSpec() = %v, wanted %v", got, test.want) } if test.want != nil { if wantWarn { test.want.Level = apis.WarningLevel } else { test.want.Level = apis.ErrorLevel } } // Check wrapped in a Pod pod := &duckv1.Pod{ Spec: *test.ps, } got = v.ValidatePod(testContext, pod) want := test.want.ViaField("spec") if (got != nil) != (want != nil) { t.Errorf("ValidatePod() = %v, wanted %v", got, want) } else if got != nil && got.Error() != want.Error() { t.Errorf("ValidatePod() = %v, wanted %v", got, want) } // Check the warning/error level. if got != nil && test.want != nil { if got.Level != want.Level { t.Errorf("ValidatePod() Wrong Level = %v, wanted %v", got.Level, want.Level) } } // Check that we don't block things being deleted. if got := v.ValidatePod(apis.WithinDelete(testContext), pod); got != nil { t.Errorf("ValidatePod() = %v, wanted nil", got) } // Check wrapped in a WithPod withPod := &duckv1.WithPod{ Spec: duckv1.WithPodSpec{ Template: duckv1.PodSpecable{ Spec: *test.ps, }, }, } got = v.ValidatePodSpecable(testContext, withPod) want = test.want.ViaField("spec.template.spec") if (got != nil) != (want != nil) { t.Errorf("ValidatePodSpecable() = %v, wanted %v", got, want) } else if got != nil && got.Error() != want.Error() { t.Errorf("ValidatePodSpecable() = %v, wanted %v", got, want) } // Check the warning/error level. if got != nil && test.want != nil { if got.Level != want.Level { t.Errorf("ValidatePodSpecable() Wrong Level = %v, wanted %v", got.Level, want.Level) } } // Check that we don't block things being deleted. if got := v.ValidatePodSpecable(apis.WithinDelete(testContext), withPod); got != nil { t.Errorf("ValidatePodSpecable() = %v, wanted nil", got) } // Check wrapped in a podScalable podScalable := &policyduckv1beta1.PodScalable{ Spec: policyduckv1beta1.PodScalableSpec{ Replicas: ptr.Int32(3), Template: corev1.PodTemplateSpec{ Spec: *test.ps, }, }, } got = v.ValidatePodScalable(testContext, podScalable) want = test.want.ViaField("spec.template.spec") if (got != nil) != (want != nil) { t.Errorf("ValidatePodScalable() = %v, wanted %v", got, want) } else if got != nil && got.Error() != want.Error() { t.Errorf("ValidatePodScalable() = %v, wanted %v", got, want) } // Check the warning/error level. if got != nil && test.want != nil { if got.Level != want.Level { t.Errorf("ValidatePodScalable() Wrong Level = %v, wanted %v", got.Level, want.Level) } } // Check that we don't block things being deleted. if got := v.ValidatePodScalable(apis.WithinDelete(testContext), podScalable); got != nil { t.Errorf("ValidatePodSpecable() = %v, wanted nil", got) } // Check that we don't block things being scaled down. original := podScalable.DeepCopy() original.Spec.Replicas = ptr.Int32(4) if got := v.ValidatePodScalable(apis.WithinUpdate(testContext, original), podScalable); got != nil { t.Errorf("ValidatePodSpecable() scaling down = %v, wanted nil", got) } // Check that we fail as expected if being scaled up. original.Spec.Replicas = ptr.Int32(2) got = v.ValidatePodScalable(apis.WithinUpdate(testContext, original), podScalable) want = test.want.ViaField("spec.template.spec") if (got != nil) != (want != nil) { t.Errorf("ValidatePodScalable() scaling up = %v, wanted %v", got, want) } else if got != nil && got.Error() != want.Error() { t.Errorf("ValidatePodScalable() scaling up = %v, wanted %v", got, want) } // Check the warning/error level. if got != nil && test.want != nil { if got.Level != want.Level { t.Errorf("ValidatePodScalable() scaling up Wrong Level = %v, wanted %v", got.Level, want.Level) } } } }) } } func TestValidateCronJob(t *testing.T) { tag := name.MustParseReference("gcr.io/distroless/static:nonroot") // Resolved via crane digest on 2021/09/25 digest := name.MustParseReference("gcr.io/distroless/static:nonroot@sha256:be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4") ctx, _ := rtesting.SetupFakeContext(t) kc := fakekube.Get(ctx) kc.CoreV1().ServiceAccounts("default").Create(ctx, &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: "default", }, }, metav1.CreateOptions{}) v := NewValidator(ctx) cvs := cosignVerifySignatures defer func() { cosignVerifySignatures = cvs }() // Let's just say that everything is verified. /*pass := func(ctx context.Context, signedImgRef name.Reference, co *cosign.CheckOpts) (checkedSignatures []oci.Signature, bundleVerified bool, err error) { sig, err := static.NewSignature(nil, "") if err != nil { return nil, false, err } return []oci.Signature{sig}, true, nil }*/ // Let's just say that everything is not verified. fail := func(_ context.Context, _ name.Reference, _ *cosign.CheckOpts) (checkedSignatures []oci.Signature, bundleVerified bool, err error) { return nil, false, errors.New("bad signature") } tests := []struct { name string c *duckv1.CronJob want *apis.FieldError cvs func(context.Context, name.Reference, *cosign.CheckOpts) ([]oci.Signature, bool, error) }{{ name: "k8schain ignore (bad service account)", c: &duckv1.CronJob{ Spec: batchv1.CronJobSpec{ JobTemplate: batchv1.JobTemplateSpec{ Spec: batchv1.JobSpec{ Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ ServiceAccountName: "not-found", InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, }, }, }, }, }, }, { name: "k8schain ignore (bad pull secret)", c: &duckv1.CronJob{ Spec: batchv1.CronJobSpec{ JobTemplate: batchv1.JobTemplateSpec{ Spec: batchv1.JobSpec{ Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ ImagePullSecrets: []corev1.LocalObjectReference{{ Name: "not-found", }}, InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, }, }, }, }, }, }, { name: "bad reference", c: &duckv1.CronJob{ Spec: batchv1.CronJobSpec{ JobTemplate: batchv1.JobTemplateSpec{ Spec: batchv1.JobSpec{ Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ Containers: []corev1.Container{{ Name: "user-container", Image: "in@valid", }}, }, }, }, }, }, }, want: &apis.FieldError{ Message: `could not parse reference: in@valid`, Paths: []string{"spec.jobTemplate.spec.template.spec.containers[0].image"}, }, cvs: fail, }, { name: "not digest", c: &duckv1.CronJob{ Spec: batchv1.CronJobSpec{ JobTemplate: batchv1.JobTemplateSpec{ Spec: batchv1.JobSpec{ Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ Containers: []corev1.Container{{ Name: "user-container", Image: tag.String(), }}, }, }, }, }, }, }, want: &apis.FieldError{ Message: `invalid value: gcr.io/distroless/static:nonroot must be an image digest`, Paths: []string{"spec.jobTemplate.spec.template.spec.containers[0].image"}, }, cvs: fail, }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { cosignVerifySignatures = test.cvs testContext := context.WithValue(context.Background(), kubeclient.Key{}, kc) // Check the core mechanics got := v.ValidateCronJob(testContext, test.c) if (got != nil) != (test.want != nil) { t.Errorf("validateCronJob() = %v, wanted %v", got, test.want) } else if got != nil && got.Error() != test.want.Error() { t.Errorf("validateCronJob() = %v, wanted %v", got, test.want) } // Check that we don't block things being deleted. cronJob := test.c.DeepCopy() if got := v.ValidateCronJob(apis.WithinDelete(testContext), cronJob); got != nil { t.Errorf("ValidateCronJob() = %v, wanted nil", got) } // Check that we don't block things already deleted. cronJob = test.c.DeepCopy() cronJob.DeletionTimestamp = &metav1.Time{Time: time.Now()} if got := v.ValidateCronJob(context.Background(), cronJob); got != nil { t.Errorf("ValidateCronJob() = %v, wanted nil", got) } }) } } func TestResolvePodSpec(t *testing.T) { tag := name.MustParseReference("gcr.io/distroless/static:nonroot") // Resolved via crane digest on 2021/09/25 digest := name.MustParseReference("gcr.io/distroless/static:nonroot@sha256:be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4") digestWithoutTag := name.MustParseReference("gcr.io/distroless/static@sha256:be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4") ctx, _ := rtesting.SetupFakeContext(t) kc := fakekube.Get(ctx) kc.CoreV1().ServiceAccounts("default").Create(ctx, &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: "default", }, }, metav1.CreateOptions{}) v := NewValidator(ctx) rrd := remoteResolveDigest defer func() { remoteResolveDigest = rrd }() resolve := func(_ name.Reference, _ ...remote.Option) (name.Digest, error) { return tag.Context().Digest(digestWithoutTag.Identifier()), nil } tests := []struct { name string ps *corev1.PodSpec want *corev1.PodSpec wc func(context.Context) context.Context rrd func(name.Reference, ...remote.Option) (name.Digest, error) }{{ name: "nothing changed (not the right update)", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: tag.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: tag.String(), }}, }, want: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: tag.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: tag.String(), }}, }, rrd: resolve, }, { name: "nothing changed (bad reference)", ps: &corev1.PodSpec{ Containers: []corev1.Container{{ Name: "user-container", Image: "in@valid", }}, }, want: &corev1.PodSpec{ Containers: []corev1.Container{{ Name: "user-container", Image: "in@valid", }}, }, wc: apis.WithinCreate, rrd: resolve, }, { name: "nothing changed (unable to resolve)", ps: &corev1.PodSpec{ Containers: []corev1.Container{{ Name: "user-container", Image: tag.String(), }}, }, want: &corev1.PodSpec{ Containers: []corev1.Container{{ Name: "user-container", Image: tag.String(), }}, }, wc: apis.WithinCreate, rrd: func(_ name.Reference, _ ...remote.Option) (name.Digest, error) { return name.Digest{}, errors.New("boom") }, }, { name: "digests resolve (in create)", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: tag.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: tag.String(), }}, }, want: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, wc: apis.WithinCreate, rrd: resolve, }, { name: "digests without tag resolve (in create)", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digestWithoutTag.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digestWithoutTag.String(), }}, }, want: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digestWithoutTag.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digestWithoutTag.String(), }}, }, wc: apis.WithinCreate, rrd: resolve, }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { remoteResolveDigest = test.rrd ctx := context.Background() if test.wc != nil { ctx = test.wc(context.Background()) } ctx = context.WithValue(ctx, kubeclient.Key{}, kc) // Check the core mechanics. got := test.ps.DeepCopy() v.resolvePodSpec(ctx, got, k8schain.Options{}) if !cmp.Equal(got, test.want) { t.Errorf("resolvePodSpec = %s", cmp.Diff(got, test.want)) } var want runtime.Object // Check wrapped in a Pod pod := &duckv1.Pod{Spec: *test.ps.DeepCopy()} want = &duckv1.Pod{Spec: *test.want.DeepCopy()} v.ResolvePod(ctx, pod) if !cmp.Equal(pod, want) { t.Errorf("ResolvePod = %s", cmp.Diff(pod, want)) } // Check that nothing happens when it's being deleted. pod = &duckv1.Pod{Spec: *test.ps.DeepCopy()} want = pod.DeepCopy() v.ResolvePod(apis.WithinDelete(ctx), pod) if !cmp.Equal(pod, want) { t.Errorf("ResolvePod = %s", cmp.Diff(pod, want)) } // Check that nothing happens when it's already deleted. pod = &duckv1.Pod{Spec: *test.ps.DeepCopy()} pod.DeletionTimestamp = &metav1.Time{Time: time.Now()} want = pod.DeepCopy() v.ResolvePod(ctx, pod) if !cmp.Equal(pod, want) { t.Errorf("ResolvePod = %s", cmp.Diff(pod, want)) } // Check wrapped in a WithPod withPod := &duckv1.WithPod{ Spec: duckv1.WithPodSpec{ Template: duckv1.PodSpecable{ Spec: *test.ps.DeepCopy(), }, }, } want = &duckv1.WithPod{ Spec: duckv1.WithPodSpec{ Template: duckv1.PodSpecable{ Spec: *test.want.DeepCopy(), }, }, } v.ResolvePodSpecable(ctx, withPod) if !cmp.Equal(withPod, want) { t.Errorf("ResolvePodSpecable = %s", cmp.Diff(withPod, want)) } // Check that nothing happens when it's being deleted. withPod = &duckv1.WithPod{ Spec: duckv1.WithPodSpec{ Template: duckv1.PodSpecable{ Spec: *test.ps.DeepCopy(), }, }, } want = withPod.DeepCopy() v.ResolvePodSpecable(apis.WithinDelete(ctx), withPod) if !cmp.Equal(withPod, want) { t.Errorf("ResolvePodSpecable = %s", cmp.Diff(withPod, want)) } // Check that nothing happens when it's already deleted. withPod = &duckv1.WithPod{ Spec: duckv1.WithPodSpec{ Template: duckv1.PodSpecable{ Spec: *test.ps.DeepCopy(), }, }, } withPod.DeletionTimestamp = &metav1.Time{Time: time.Now()} want = withPod.DeepCopy() v.ResolvePodSpecable(ctx, withPod) if !cmp.Equal(withPod, want) { t.Errorf("ResolvePodSpecable = %s", cmp.Diff(withPod, want)) } // Check wrapped in a PodScalable podScalable := &policyduckv1beta1.PodScalable{ Spec: policyduckv1beta1.PodScalableSpec{ Replicas: ptr.Int32(3), Template: corev1.PodTemplateSpec{ Spec: *test.ps.DeepCopy(), }, }, } want = &policyduckv1beta1.PodScalable{ Spec: policyduckv1beta1.PodScalableSpec{ Replicas: ptr.Int32(3), Template: corev1.PodTemplateSpec{ Spec: *test.want.DeepCopy(), }, }, } v.ResolvePodScalable(ctx, podScalable) if !cmp.Equal(podScalable, want) { t.Errorf("ResolvePodSpecable = %s", cmp.Diff(podScalable, want)) } // Check that nothing happens when it's being deleted. podScalable = &policyduckv1beta1.PodScalable{ Spec: policyduckv1beta1.PodScalableSpec{ Replicas: ptr.Int32(2), Template: corev1.PodTemplateSpec{ Spec: *test.ps.DeepCopy(), }, }, } want = podScalable.DeepCopy() v.ResolvePodScalable(apis.WithinDelete(ctx), podScalable) if !cmp.Equal(podScalable, want) { t.Errorf("ResolvePodSpecable = %s", cmp.Diff(podScalable, want)) } // Check that nothing happens when it's already deleted. podScalable = &policyduckv1beta1.PodScalable{ Spec: policyduckv1beta1.PodScalableSpec{ Replicas: ptr.Int32(2), Template: corev1.PodTemplateSpec{ Spec: *test.ps.DeepCopy(), }, }, } podScalable.DeletionTimestamp = &metav1.Time{Time: time.Now()} want = podScalable.DeepCopy() v.ResolvePodScalable(ctx, podScalable) if !cmp.Equal(podScalable, want) { t.Errorf("ResolvePodSpecable = %s", cmp.Diff(podScalable, want)) } // Check that nothing happens when it's being scaled down. podScalable = &policyduckv1beta1.PodScalable{ Spec: policyduckv1beta1.PodScalableSpec{ Replicas: ptr.Int32(2), Template: corev1.PodTemplateSpec{ Spec: *test.ps.DeepCopy(), }, }, } want = podScalable.DeepCopy() original := &policyduckv1beta1.PodScalable{ Spec: policyduckv1beta1.PodScalableSpec{ Replicas: ptr.Int32(3), Template: corev1.PodTemplateSpec{ Spec: *test.ps.DeepCopy(), }, }, } v.ResolvePodScalable(apis.WithinUpdate(ctx, original), podScalable) if !cmp.Equal(podScalable, want) { t.Errorf("ResolvePodSpecable = %s", cmp.Diff(podScalable, want)) } }) } } func TestResolveCronJob(t *testing.T) { tag := name.MustParseReference("gcr.io/distroless/static:nonroot") // Resolved via crane digest on 2021/09/25 digest := name.MustParseReference("gcr.io/distroless/static:nonroot@sha256:be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4") ctx, _ := rtesting.SetupFakeContext(t) kc := fakekube.Get(ctx) kc.CoreV1().ServiceAccounts("default").Create(ctx, &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: "default", }, }, metav1.CreateOptions{}) v := NewValidator(ctx) rrd := remoteResolveDigest defer func() { remoteResolveDigest = rrd }() resolve := func(_ name.Reference, _ ...remote.Option) (name.Digest, error) { return digest.(name.Digest), nil } tests := []struct { name string c *duckv1.CronJob want *duckv1.CronJob wc func(context.Context) context.Context rrd func(name.Reference, ...remote.Option) (name.Digest, error) }{{ name: "nothing changed (not the right update)", c: &duckv1.CronJob{ Spec: batchv1.CronJobSpec{ JobTemplate: batchv1.JobTemplateSpec{ Spec: batchv1.JobSpec{ Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: tag.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: tag.String(), }}, }, }, }, }, }, }, want: &duckv1.CronJob{ Spec: batchv1.CronJobSpec{ JobTemplate: batchv1.JobTemplateSpec{ Spec: batchv1.JobSpec{ Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: tag.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: tag.String(), }}, }, }, }, }, }, }, rrd: resolve, }, { name: "nothing changed (bad reference)", c: &duckv1.CronJob{ Spec: batchv1.CronJobSpec{ JobTemplate: batchv1.JobTemplateSpec{ Spec: batchv1.JobSpec{ Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ Containers: []corev1.Container{{ Name: "user-container", Image: "in@valid", }}, }, }, }, }, }, }, want: &duckv1.CronJob{ Spec: batchv1.CronJobSpec{ JobTemplate: batchv1.JobTemplateSpec{ Spec: batchv1.JobSpec{ Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ Containers: []corev1.Container{{ Name: "user-container", Image: "in@valid", }}, }, }, }, }, }, }, wc: apis.WithinCreate, rrd: resolve, }, { name: "nothing changed (unable to resolve)", c: &duckv1.CronJob{ Spec: batchv1.CronJobSpec{ JobTemplate: batchv1.JobTemplateSpec{ Spec: batchv1.JobSpec{ Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ Containers: []corev1.Container{{ Name: "user-container", Image: "in@valid", }}, }, }, }, }, }, }, want: &duckv1.CronJob{ Spec: batchv1.CronJobSpec{ JobTemplate: batchv1.JobTemplateSpec{ Spec: batchv1.JobSpec{ Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ Containers: []corev1.Container{{ Name: "user-container", Image: "in@valid", }}, }, }, }, }, }, }, wc: apis.WithinCreate, rrd: func(_ name.Reference, _ ...remote.Option) (name.Digest, error) { return name.Digest{}, errors.New("boom") }, }, { name: "digests resolve (in create)", c: &duckv1.CronJob{ Spec: batchv1.CronJobSpec{ JobTemplate: batchv1.JobTemplateSpec{ Spec: batchv1.JobSpec{ Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: tag.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: tag.String(), }}, }, }, }, }, }, }, want: &duckv1.CronJob{ Spec: batchv1.CronJobSpec{ JobTemplate: batchv1.JobTemplateSpec{ Spec: batchv1.JobSpec{ Template: corev1.PodTemplateSpec{ Spec: corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, }, }, }, }, }, wc: apis.WithinCreate, rrd: resolve, }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { remoteResolveDigest = test.rrd ctx := context.Background() if test.wc != nil { ctx = test.wc(context.Background()) } ctx = context.WithValue(ctx, kubeclient.Key{}, kc) var want runtime.Object cronJob := test.c.DeepCopy() want = test.want.DeepCopy() v.ResolveCronJob(ctx, cronJob) if !cmp.Equal(cronJob, want) { t.Errorf("ResolveCronJob = %s", cmp.Diff(cronJob, want)) } // Check that nothing happens when it's being deleted. cronJob = test.c.DeepCopy() want = cronJob.DeepCopy() v.ResolveCronJob(apis.WithinDelete(ctx), cronJob) if !cmp.Equal(cronJob, want) { t.Errorf("ResolveCronJob = %s", cmp.Diff(cronJob, want)) } }) } } func TestValidatePolicy(t *testing.T) { // Resolved via crane digest on 2021/09/25 digest := name.MustParseReference("gcr.io/distroless/static:nonroot@sha256:be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4") // Non-existent URL for testing complete failure badURL := apis.HTTP("http://example.com/") t.Logf("badURL: %s", badURL.String()) // Spin up a Fulcio that responds with a Root Cert fulcioServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { rw.Write([]byte(fulcioRootCert)) })) t.Cleanup(fulcioServer.Close) fulcioURL, err := apis.ParseURL("https://fulcio.sigstore.dev") if err != nil { t.Fatalf("Failed to parse fake Fulcio URL") } rekorServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { rw.Write([]byte(rekorResponse)) })) t.Cleanup(rekorServer.Close) rekorURL, err := apis.ParseURL(rekorServer.URL) if err != nil { t.Fatalf("Failed to parse fake Rekor URL") } t.Logf("rekorURL: %s", rekorURL.String()) var authorityKeyCosignPub *ecdsa.PublicKey pems := parsePems([]byte(authorityKeyCosignPubString)) if len(pems) > 0 { key, _ := x509.ParsePKIXPublicKey(pems[0].Bytes) authorityKeyCosignPub = key.(*ecdsa.PublicKey) } else { t.Errorf("Error parsing authority key from string") } cvs := cosignVerifySignatures defer func() { cosignVerifySignatures = cvs }() // Let's just say that everything is verified. pass := func(_ context.Context, _ name.Reference, _ *cosign.CheckOpts) (checkedSignatures []oci.Signature, bundleVerified bool, err error) { sig, err := static.NewSignature(nil, "") if err != nil { return nil, false, err } return []oci.Signature{sig}, true, nil } // Let's just say that everything is verified. passKeyless := func(_ context.Context, _ name.Reference, _ *cosign.CheckOpts, _ ...name.Option) (checkedSignatures []oci.Signature, bundleVerified bool, err error) { // This is from 2022/07/29 // ghcr.io/distroless/static@sha256:a1e82f6a5f6dfc735165d3442e7cc5a615f72abac3db19452481f5f3c90fbfa8 payload := []byte(`{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL2Nvc2lnbi5zaWdzdG9yZS5kZXYvYXR0ZXN0YXRpb24vdnVsbi92MSIsInN1YmplY3QiOlt7Im5hbWUiOiJnaGNyLmlvL2Rpc3Ryb2xlc3Mvc3RhdGljIiwiZGlnZXN0Ijp7InNoYTI1NiI6ImExZTgyZjZhNWY2ZGZjNzM1MTY1ZDM0NDJlN2NjNWE2MTVmNzJhYmFjM2RiMTk0NTI0ODFmNWYzYzkwZmJmYTgifX1dLCJwcmVkaWNhdGUiOnsiaW52b2NhdGlvbiI6eyJwYXJhbWV0ZXJzIjpudWxsLCJ1cmkiOiJodHRwczovL2dpdGh1Yi5jb20vZGlzdHJvbGVzcy9zdGF0aWMvYWN0aW9ucy9ydW5zLzI3NTc5NTMxMzkiLCJldmVudF9pZCI6IjI3NTc5NTMxMzkiLCJidWlsZGVyLmlkIjoiQ3JlYXRlIFJlbGVhc2UifSwic2Nhbm5lciI6eyJ1cmkiOiJodHRwczovL2dpdGh1Yi5jb20vYXF1YXNlY3VyaXR5L3RyaXZ5IiwidmVyc2lvbiI6IjAuMjkuMiIsImRiIjp7InVyaSI6IiIsInZlcnNpb24iOiIifSwicmVzdWx0Ijp7IiRzY2hlbWEiOiJodHRwczovL2pzb24uc2NoZW1hc3RvcmUub3JnL3NhcmlmLTIuMS4wLXJ0bS41Lmpzb24iLCJydW5zIjpbeyJjb2x1bW5LaW5kIjoidXRmMTZDb2RlVW5pdHMiLCJvcmlnaW5hbFVyaUJhc2VJZHMiOnsiUk9PVFBBVEgiOnsidXJpIjoiZmlsZTovLy8ifX0sInJlc3VsdHMiOltdLCJ0b29sIjp7ImRyaXZlciI6eyJmdWxsTmFtZSI6IlRyaXZ5IFZ1bG5lcmFiaWxpdHkgU2Nhbm5lciIsImluZm9ybWF0aW9uVXJpIjoiaHR0cHM6Ly9naXRodWIuY29tL2FxdWFzZWN1cml0eS90cml2eSIsIm5hbWUiOiJUcml2eSIsInJ1bGVzIjpbXSwidmVyc2lvbiI6IjAuMjkuMiJ9fX1dLCJ2ZXJzaW9uIjoiMi4xLjAifX0sIm1ldGFkYXRhIjp7InNjYW5TdGFydGVkT24iOiIyMDIyLTA3LTI5VDAyOjI4OjQyWiIsInNjYW5GaW5pc2hlZE9uIjoiMjAyMi0wNy0yOVQwMjoyODo0OFoifX19","signatures":[{"keyid":"","sig":"MEYCIQDeQXMMojIpNvxEDLDXUC5aAwCbPPr/0uckP8TCcdTLjgIhAJG6M00kY40bz/C90W0FeUc2YcWY+txD4BPXhzd8E+tP"}]}`) set, err := base64.StdEncoding.DecodeString("MEQCIDBYWwwDW+nH+1vFoTOqHS4jAtVm4Yezq2nAy7vjcV8zAiBkznmgMrz9em4NuB/hl5X/umubhLgwoXgUAY2NJJwu5A==") if err != nil { return nil, false, err } sig, err := static.NewSignature(payload, "", static.WithCertChain( []byte("-----BEGIN CERTIFICATE-----\nMIIDnDCCAyOgAwIBAgIUVGZ4TQgYi4VCLLFghYMU/taKrD8wCgYIKoZIzj0EAwMw\nNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl\ncm1lZGlhdGUwHhcNMjIwNzI5MDIyODQ4WhcNMjIwNzI5MDIzODQ4WjAAMFkwEwYH\nKoZIzj0CAQYIKoZIzj0DAQcDQgAEhiVvK5Tqk1+HnXSstf/8byA1RDpZu+Jvn9X6\nZoaCL/IjSJ7fBakvKAQ0BlzFg/JEtDreg/TFNiX2wnlMBlMV16OCAkIwggI+MA4G\nA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUiMn3\nza+9v+99n385GpkXzZxZiBIwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y\nZD8wYQYDVR0RAQH/BFcwVYZTaHR0cHM6Ly9naXRodWIuY29tL2Rpc3Ryb2xlc3Mv\nc3RhdGljLy5naXRodWIvd29ya2Zsb3dzL3JlbGVhc2UueWFtbEByZWZzL2hlYWRz\nL21haW4wOQYKKwYBBAGDvzABAQQraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1\nYnVzZXJjb250ZW50LmNvbTAWBgorBgEEAYO/MAECBAhzY2hlZHVsZTA2BgorBgEE\nAYO/MAEDBCg3ZTc1NzJlNTc4ZGU3YzUxYTJmMWExNzkxZjAyNWNmMzE1NTAzYWEy\nMBwGCisGAQQBg78wAQQEDkNyZWF0ZSBSZWxlYXNlMB8GCisGAQQBg78wAQUEEWRp\nc3Ryb2xlc3Mvc3RhdGljMB0GCisGAQQBg78wAQYED3JlZnMvaGVhZHMvbWFpbjCB\nigYKKwYBBAHWeQIEAgR8BHoAeAB2AAhgkvAoUv9oRdHRayeEnEVnGKwWPcM40m3m\nvCIGNm9yAAABgkfI9c8AAAQDAEcwRQIgPm4AoftGQF2abbFxMLvtzTjXy+sxwxTp\nCh5ZsoesBDMCIQCNlwmLpuu1KiqjY74l5527AffSd4kOapDMfpHAlMrpCTAKBggq\nhkjOPQQDAwNnADBkAjAe7jfVc1OJNhbaZF8BJRJ9nQOAcY6kwFYMav1XfQsJPE0x\naYpNg/oXVA5UrFcSBLkCMFa4124w3qUzrXSTGq99nlALKQ8HFR8ri17wM5/ZiWxi\nrtABq5eub32TXpAnfqGSmw==\n-----END CERTIFICATE-----\n"), []byte("-----BEGIN CERTIFICATE-----\nMIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMw\nKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y\nMjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3Jl\nLmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0C\nAQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV7\n7LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS\n0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYB\nBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjp\nKFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZI\nzj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJR\nnZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsP\nmygUY7Ii2zbdCdliiow=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMw\nKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y\nMTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3Jl\nLmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7\nXeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxex\nX69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92j\nYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRY\nwB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQ\nKsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCM\nWP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9\nTNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ\n-----END CERTIFICATE-----"), ), static.WithBundle(&bundle.RekorBundle{ SignedEntryTimestamp: set, Payload: bundle.RekorPayload{ Body: "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaW50b3RvIiwic3BlYyI6eyJjb250ZW50Ijp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiIyYjY1Y2JmMGU3OTAxYmEzMWQ1NWIxMmQzMTliY2EzOTQyMGFmNDM4OGQzZTU3MTRkMTZmMjAxOWQ3NGUzYWI3In0sInBheWxvYWRIYXNoIjp7ImFsZ29yaXRobSI6InNoYTI1NiIsInZhbHVlIjoiYzFiNWYwZjRiOGVjZDU1ZWRhMjUwY2Q4NDk2NGQwYzFmYjVkN2E4YTM0OGY0YjdmZmI3ZGFhMmUwNmM0ODM3MyJ9fSwicHVibGljS2V5IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVUnVSRU5EUVhsUFowRjNTVUpCWjBsVlZrZGFORlJSWjFscE5GWkRURXhHWjJoWlRWVXZkR0ZMY2tRNGQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcEpkMDU2U1RWTlJFbDVUMFJSTkZkb1kwNU5ha2wzVG5wSk5VMUVTWHBQUkZFMFYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZvYVZaMlN6VlVjV3N4SzBodVdGTnpkR1l2T0dKNVFURlNSSEJhZFN0S2RtNDVXRFlLV205aFEwd3ZTV3BUU2pkbVFtRnJka3RCVVRCQ2JIcEdaeTlLUlhSRWNtVm5MMVJHVG1sWU1uZHViRTFDYkUxV01UWlBRMEZyU1hkblowa3JUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXUkNaMDVXU0ZFMFJVWm5VVlZwVFc0ekNucGhLemwyS3prNWJqTTROVWR3YTFoNlduaGFhVUpKZDBoM1dVUldVakJxUWtKbmQwWnZRVlV6T1ZCd2VqRlphMFZhWWpWeFRtcHdTMFpYYVhocE5Ga0tXa1E0ZDFsUldVUldVakJTUVZGSUwwSkdZM2RXV1ZwVVlVaFNNR05JVFRaTWVUbHVZVmhTYjJSWFNYVlpNamwwVERKU2NHTXpVbmxpTW5oc1l6Tk5kZ3BqTTFKb1pFZHNha3g1Tlc1aFdGSnZaRmRKZG1ReU9YbGhNbHB6WWpOa2Vrd3pTbXhpUjFab1l6SlZkV1ZYUm5SaVJVSjVXbGRhZWt3eWFHeFpWMUo2Q2t3eU1XaGhWelIzVDFGWlMwdDNXVUpDUVVkRWRucEJRa0ZSVVhKaFNGSXdZMGhOTmt4NU9UQmlNblJzWW1rMWFGa3pVbkJpTWpWNlRHMWtjR1JIYURFS1dXNVdlbHBZU21waU1qVXdXbGMxTUV4dFRuWmlWRUZYUW1kdmNrSm5SVVZCV1U4dlRVRkZRMEpCYUhwWk1taHNXa2hXYzFwVVFUSkNaMjl5UW1kRlJRcEJXVTh2VFVGRlJFSkRaek5hVkdNeFRucEtiRTVVWXpSYVIxVXpXWHBWZUZsVVNtMU5WMFY0VG5wcmVGcHFRWGxPVjA1dFRYcEZNVTVVUVhwWlYwVjVDazFDZDBkRGFYTkhRVkZSUW1jM09IZEJVVkZGUkd0T2VWcFhSakJhVTBKVFdsZDRiRmxZVG14TlFqaEhRMmx6UjBGUlVVSm5OemgzUVZGVlJVVlhVbkFLWXpOU2VXSXllR3hqTTAxMll6TlNhR1JIYkdwTlFqQkhRMmx6UjBGUlVVSm5OemgzUVZGWlJVUXpTbXhhYmsxMllVZFdhRnBJVFhaaVYwWndZbXBEUWdwcFoxbExTM2RaUWtKQlNGZGxVVWxGUVdkU09FSkliMEZsUVVJeVFVRm9aMnQyUVc5VmRqbHZVbVJJVW1GNVpVVnVSVlp1UjB0M1YxQmpUVFF3YlROdENuWkRTVWRPYlRsNVFVRkJRbWRyWmtrNVl6aEJRVUZSUkVGRlkzZFNVVWxuVUcwMFFXOW1kRWRSUmpKaFltSkdlRTFNZG5SNlZHcFllU3R6ZUhkNFZIQUtRMmcxV25OdlpYTkNSRTFEU1ZGRFRteDNiVXh3ZFhVeFMybHhhbGszTkd3MU5USTNRV1ptVTJRMGEwOWhjRVJOWm5CSVFXeE5jbkJEVkVGTFFtZG5jUXBvYTJwUFVGRlJSRUYzVG01QlJFSnJRV3BCWlRkcVpsWmpNVTlLVG1oaVlWcEdPRUpLVWtvNWJsRlBRV05aTm10M1JsbE5ZWFl4V0daUmMwcFFSVEI0Q21GWmNFNW5MMjlZVmtFMVZYSkdZMU5DVEd0RFRVWmhOREV5TkhjemNWVjZjbGhUVkVkeE9UbHViRUZNUzFFNFNFWlNPSEpwTVRkM1RUVXZXbWxYZUdrS2NuUkJRbkUxWlhWaU16SlVXSEJCYm1aeFIxTnRkejA5Q2kwdExTMHRSVTVFSUVORlVsUkpSa2xEUVZSRkxTMHRMUzBLIn19", IntegratedTime: 1659061729, LogIndex: 3059470, LogID: "c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d", }, })) if err != nil { return nil, false, err } return []oci.Signature{sig}, true, nil } // Let's just say that everything is not verified. fail := func(_ context.Context, _ name.Reference, _ *cosign.CheckOpts) (checkedSignatures []oci.Signature, bundleVerified bool, err error) { return nil, false, errors.New("bad signature") } // Let's say it is verified if it is the expected Public Key authorityPublicKeyCVS := func(ctx context.Context, signedImgRef name.Reference, co *cosign.CheckOpts) (checkedSignatures []oci.Signature, bundleVerified bool, err error) { // Because we use this below and it gets called for both key / keyless // in the keyless case there's no SigVerifier, so fail it. if co.SigVerifier == nil { return nil, false, errors.New("Keyless used for key") } actualPublicKey, _ := co.SigVerifier.PublicKey() actualECDSAPubkey := actualPublicKey.(*ecdsa.PublicKey) actualPubKey, err := actualECDSAPubkey.ECDH() if err != nil { return nil, false, errors.New("failed to get edch pub key") } authorityKeyPubKey, err := authorityKeyCosignPub.ECDH() if err != nil { return nil, false, errors.New("failed to get edch pub key") } if bytes.Equal(actualPubKey.Bytes(), authorityKeyPubKey.Bytes()) { return pass(ctx, signedImgRef, co) } return fail(ctx, signedImgRef, co) } tests := []struct { name string policy webhookcip.ClusterImagePolicy want *PolicyResult wantErrs []string cva func(context.Context, name.Reference, *cosign.CheckOpts, ...name.Option) ([]oci.Signature, bool, error) cvs func(context.Context, name.Reference, *cosign.CheckOpts) ([]oci.Signature, bool, error) customContext context.Context }{{ name: "fail with no public key", policy: webhookcip.ClusterImagePolicy{ Authorities: []webhookcip.Authority{{ Name: "authority-0", Key: &webhookcip.KeyRef{}, }}, }, wantErrs: []string{"there are no public keys for authority authority-0"}, }, { name: "simple, public key, no matches", policy: webhookcip.ClusterImagePolicy{ Authorities: []webhookcip.Authority{{ Name: "authority-0", Key: &webhookcip.KeyRef{ PublicKeys: []crypto.PublicKey{authorityKeyCosignPub}, HashAlgorithm: signaturealgo.DefaultSignatureAlgorithm, HashAlgorithmCode: crypto.SHA256, }, }}, }, wantErrs: []string{"key validation failed for authority authority-0 for gcr.io/distroless/static@sha256:be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4: bad signature"}, cvs: fail, }, { name: "simple, public key, works", policy: webhookcip.ClusterImagePolicy{ Authorities: []webhookcip.Authority{{ Name: "authority-0", Key: &webhookcip.KeyRef{ PublicKeys: []crypto.PublicKey{authorityKeyCosignPub}, HashAlgorithm: signaturealgo.DefaultSignatureAlgorithm, HashAlgorithmCode: crypto.SHA256, }, }}, }, want: &PolicyResult{ AuthorityMatches: map[string]AuthorityMatch{ "authority-0": { Signatures: []PolicySignature{{ ID: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", // TODO(mattmoor): Is there anything we should encode for key-based? }}, }}, }, cvs: pass, }, { name: "simple, public key and keyless, one works, one doesn't", policy: webhookcip.ClusterImagePolicy{ Authorities: []webhookcip.Authority{{ Name: "authority-0", Key: &webhookcip.KeyRef{ PublicKeys: []crypto.PublicKey{authorityKeyCosignPub}, HashAlgorithm: signaturealgo.DefaultSignatureAlgorithm, HashAlgorithmCode: crypto.SHA256, }, }, { Name: "authority-1", Keyless: &webhookcip.KeylessRef{ URL: badURL, }, }}, }, want: &PolicyResult{ AuthorityMatches: map[string]AuthorityMatch{ "authority-0": { Signatures: []PolicySignature{{ ID: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", // TODO(mattmoor): Is there anything we should encode for key-based? }}, }}, }, wantErrs: []string{`signature keyless validation failed for authority authority-1 for gcr.io/distroless/static@sha256:be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4: Keyless used for key`}, cvs: authorityPublicKeyCVS, }, { name: "simple, static set to pass", policy: webhookcip.ClusterImagePolicy{ Authorities: []webhookcip.Authority{{ Name: "authority-0", Static: &webhookcip.StaticRef{ Action: "pass", }, }}, }, want: &PolicyResult{ AuthorityMatches: map[string]AuthorityMatch{ "authority-0": { Static: true, }, }, }, }, { name: "simple, static set to fail", policy: webhookcip.ClusterImagePolicy{ Authorities: []webhookcip.Authority{{ Name: "authority-0", Static: &webhookcip.StaticRef{ Action: "fail", }, }}, }, wantErrs: []string{"disallowed by static policy"}, }, { name: "simple, static set to fail with custom message", policy: webhookcip.ClusterImagePolicy{ Authorities: []webhookcip.Authority{{ Name: "authority-0", Static: &webhookcip.StaticRef{ Action: "fail", Message: "test custom message here", }, }}, }, wantErrs: []string{"disallowed by static policy: test custom message here"}, }, { name: "simple, public key, no error", policy: webhookcip.ClusterImagePolicy{ Authorities: []webhookcip.Authority{{ Name: "authority-0", Key: &webhookcip.KeyRef{ PublicKeys: []crypto.PublicKey{authorityKeyCosignPub}, HashAlgorithm: signaturealgo.DefaultSignatureAlgorithm, HashAlgorithmCode: crypto.SHA256, }, }}, }, want: &PolicyResult{ AuthorityMatches: map[string]AuthorityMatch{ "authority-0": { Signatures: []PolicySignature{{ ID: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", // TODO(mattmoor): Is there anything we should encode for key-based? }}, }}, }, cvs: authorityPublicKeyCVS, }, { name: "simple, keyless attestation, works", policy: webhookcip.ClusterImagePolicy{ Authorities: []webhookcip.Authority{{ Name: "authority-0", Keyless: &webhookcip.KeylessRef{ URL: fulcioURL, }, Attestations: []webhookcip.AttestationPolicy{{ Name: "test-att", PredicateType: "vuln", }}, }, }, }, want: &PolicyResult{ AuthorityMatches: map[string]AuthorityMatch{ "authority-0": { Attestations: map[string][]PolicyAttestation{ "test-att": {{ PolicySignature: PolicySignature{ ID: "00016978d0723c9bc73c599d296ab4052a392e37746509c1f5038494ca4bf34a", Subject: "https://github.com/distroless/static/.github/workflows/release.yaml@refs/heads/main", Issuer: "https://token.actions.githubusercontent.com", GithubExtensions: GithubExtensions{ WorkflowTrigger: "schedule", WorkflowSHA: "7e7572e578de7c51a2f1a1791f025cf315503aa2", WorkflowName: "Create Release", WorkflowRepo: "distroless/static", WorkflowRef: "refs/heads/main", }, }, PredicateType: "vuln", Digest: "sha256:01bd6aec99ad7c5d045d9aab649fd95b7af2b3b23887d34d7fce8b2e3c38ca0e", Payload: []byte(`{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://cosign.sigstore.dev/attestation/vuln/v1","subject":[{"name":"ghcr.io/distroless/static","digest":{"sha256":"a1e82f6a5f6dfc735165d3442e7cc5a615f72abac3db19452481f5f3c90fbfa8"}}],"predicate":{"invocation":{"parameters":null,"uri":"https://github.com/distroless/static/actions/runs/2757953139","event_id":"2757953139","builder.id":"Create Release"},"scanner":{"uri":"https://github.com/aquasecurity/trivy","version":"0.29.2","db":{"uri":"","version":""},"result":{"$schema":"https://json.schemastore.org/sarif-2.1.0-rtm.5.json","runs":[{"columnKind":"utf16CodeUnits","originalUriBaseIds":{"ROOTPATH":{"uri":"file:///"}},"results":[],"tool":{"driver":{"fullName":"Trivy Vulnerability Scanner","informationUri":"https://github.com/aquasecurity/trivy","name":"Trivy","rules":[],"version":"0.29.2"}}}],"version":"2.1.0"}},"metadata":{"scanStartedOn":"2022-07-29T02:28:42Z","scanFinishedOn":"2022-07-29T02:28:48Z"}}}`), }}, }, }, }, }, cva: passKeyless, }, { name: "simple, wrong predicate keyless attestation, error", policy: webhookcip.ClusterImagePolicy{ Authorities: []webhookcip.Authority{{ Name: "authority-0", Keyless: &webhookcip.KeylessRef{ URL: fulcioURL, }, Attestations: []webhookcip.AttestationPolicy{{ Name: "test-att", PredicateType: "custom", // attestation with predicate type vuln }}, }, }, }, wantErrs: []string{"no matching attestations with type custom, checked the following predicateTypes: \"https://cosign.sigstore.dev/attestation/vuln/v1\""}, cva: passKeyless, }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { cosignVerifySignatures = test.cvs cosignVerifyAttestations = test.cva testContext := context.Background() if test.customContext != nil { testContext = test.customContext } kc, err := k8schain.NewNoClient(testContext) if err != nil { t.Fatalf("Failed to construct no client k8schain for testing") } got, gotErrs := ValidatePolicy(testContext, system.Namespace(), digest, test.policy, kc) validateErrors(t, test.wantErrs, gotErrs) if diff := cmp.Diff(test.want, got); diff != "" { t.Errorf("unexpected PolicyResult, %s", diff) } }) } } func TestValidatePolicyAttestation(t *testing.T) { // Resolved via crane digest on 2023/08/08 digestAtt := name.MustParseReference("ghcr.io/mattmoor/sbom-attestations/spdx-test@sha256:ba4037061b76ad8f306dd9e442877236015747ec42141caf504dc0df4d10708d") attPayload := []byte(`{"_type":"https://in-toto.io/Statement/v0.1","predicateType":"https://spdx.dev/Document","subject":[{"name":"ghcr.io/chainguard-dev/log4shell-demo/app","digest":{"sha256":"ba4037061b76ad8f306dd9e442877236015747ec42141caf504dc0df4d10708d"}}],"predicate":{"Data":{"Reviews":[],"SPDXID":"SPDXRef-SPDXRef-DOCUMENT","annotations":[],"creationInfo":{"comment":"","created":"2022-06-08T15:31:05Z","creators":["Tool: spdx-maven-plugin"],"licenseListVersion":"3.5"},"dataLicense":"CC0-1.0","documentNamespace":"http://spdx.org/spdxpackages/log4shell-1.0-SNAPSHOT","files":[],"hasExtractedLicensingInfos":[],"name":"log4shell","packages":[{"Files":null,"IsFilesAnalyzedTagPresent":true,"IsUnpackaged":false,"SPDXID":"SPDXRef-4","annotations":null,"checksums":null,"comment":"This package was created for a Maven dependency. No SPDX or license information could be found in the Maven POM file.","copyrightText":"UNSPECIFIED","downloadLocation":"NOASSERTION","licenseConcluded":"NOASSERTION","licenseDeclared":"NOASSERTION","licenseInfoFromFiles":["NOASSERTION"],"name":"javax.servlet-api","packageVerificationCode":{"packageVerificationCodeExcludedFiles":null,"packageVerificationCodeValue":""},"versionInfo":"4.0.1"},{"Files":null,"IsFilesAnalyzedTagPresent":true,"IsUnpackaged":false,"SPDXID":"SPDXRef-9","annotations":null,"checksums":null,"comment":"This package was created for a Maven dependency. No SPDX or license information could be found in the Maven POM file.","copyrightText":"UNSPECIFIED","downloadLocation":"NOASSERTION","licenseConcluded":"NOASSERTION","licenseDeclared":"NOASSERTION","licenseInfoFromFiles":["NOASSERTION"],"name":"log4j-api","packageVerificationCode":{"packageVerificationCodeExcludedFiles":null,"packageVerificationCodeValue":""},"versionInfo":"2.14.1"},{"Files":null,"IsFilesAnalyzedTagPresent":true,"IsUnpackaged":false,"SPDXID":"SPDXRef-7","annotations":null,"checksums":null,"comment":"This package was created for a Maven dependency. No SPDX or license information could be found in the Maven POM file.","copyrightText":"UNSPECIFIED","downloadLocation":"NOASSERTION","licenseConcluded":"NOASSERTION","licenseDeclared":"NOASSERTION","licenseInfoFromFiles":["NOASSERTION"],"name":"deploy-jar","packageVerificationCode":{"packageVerificationCodeExcludedFiles":null,"packageVerificationCodeValue":""},"versionInfo":"1.0"},{"Files":null,"IsFilesAnalyzedTagPresent":true,"IsUnpackaged":false,"SPDXID":"SPDXRef-6","annotations":null,"checksums":null,"comment":"This package was created for a Maven dependency. No SPDX or license information could be found in the Maven POM file.","copyrightText":"UNSPECIFIED","downloadLocation":"NOASSERTION","licenseConcluded":"NOASSERTION","licenseDeclared":"NOASSERTION","licenseInfoFromFiles":["NOASSERTION"],"name":"junit-jupiter-engine","packageVerificationCode":{"packageVerificationCodeExcludedFiles":null,"packageVerificationCodeValue":""},"versionInfo":"5.7.1"},{"Files":null,"IsFilesAnalyzedTagPresent":true,"IsUnpackaged":false,"SPDXID":"SPDXRef-8","annotations":null,"checksums":null,"comment":"This package was created for a Maven dependency. No SPDX or license information could be found in the Maven POM file.","copyrightText":"UNSPECIFIED","downloadLocation":"NOASSERTION","licenseConcluded":"NOASSERTION","licenseDeclared":"NOASSERTION","licenseInfoFromFiles":["NOASSERTION"],"name":"log4j-core","packageVerificationCode":{"packageVerificationCodeExcludedFiles":null,"packageVerificationCodeValue":""},"versionInfo":"2.14.1"},{"Files":null,"IsFilesAnalyzedTagPresent":true,"IsUnpackaged":false,"SPDXID":"SPDXRef-5","annotations":null,"checksums":null,"comment":"This package was created for a Maven dependency. No SPDX or license information could be found in the Maven POM file.","copyrightText":"UNSPECIFIED","downloadLocation":"NOASSERTION","licenseConcluded":"NOASSERTION","licenseDeclared":"NOASSERTION","licenseInfoFromFiles":["NOASSERTION"],"name":"junit-jupiter-api","packageVerificationCode":{"packageVerificationCodeExcludedFiles":null,"packageVerificationCodeValue":""},"versionInfo":"5.7.1"},{"Files":[{"SPDXID":"SPDXRef-2","checksums":[{"algorithm":"SHA1","checksumValue":"9e58ba0426bed767f8da4d76afde1ee629d97c41"}],"copyrightText":"http://spdx.org/rdf/terms#noassertion","fileName":"./src/main/java/com/example/log4shell/log4j.java","fileTypes":["source"],"licenseConcluded":"NOASSERTION","licenseInfoInFiles":["NOASSERTION"]},{"SPDXID":"SPDXRef-3","checksums":[{"algorithm":"SHA1","checksumValue":"26df176b1904e473fddc8ca654bce5607b3fc64f"}],"copyrightText":"","fileName":"./src/main/java/com/example/log4shell/LoginServlet.java","fileTypes":["source"],"licenseConcluded":"NOASSERTION","licenseInfoInFiles":["NOASSERTION"]}],"IsFilesAnalyzedTagPresent":true,"IsUnpackaged":false,"SPDXID":"SPDXRef-1","annotations":null,"checksums":null,"copyrightText":"http://spdx.org/rdf/terms#noassertion","downloadLocation":"NOASSERTION","filesAnalyzed":true,"licenseConcluded":"NOASSERTION","licenseDeclared":"NOASSERTION","licenseInfoFromFiles":["NOASSERTION"],"name":"log4shell","packageFileName":"http://spdx.org/rdf/terms#noassertion","packageVerificationCode":{"packageVerificationCodeExcludedFiles":null,"packageVerificationCodeValue":"b5dabb87df1acb05636fe4dbc19afdfe18298a38"},"versionInfo":"1.0-SNAPSHOT"}],"relationships":[{"comment":"Relationship based on Maven POM file dependency information","relatedSpdxElement":"SPDXRef-4","relationshipType":"other","spdxElementId":"SPDXRef-1"},{"comment":"Relationship based on Maven POM file dependency information","relatedSpdxElement":"SPDXRef-9","relationshipType":"dynamicLink","spdxElementId":"SPDXRef-1"},{"comment":"Relationship based on Maven POM file dependency information","relatedSpdxElement":"SPDXRef-7","relationshipType":"other","spdxElementId":"SPDXRef-1"},{"relatedSpdxElement":"SPDXRef-1","relationshipType":"generates","spdxElementId":"SPDXRef-2"},{"comment":"Relationship based on Maven POM file dependency information","relatedSpdxElement":"SPDXRef-6","relationshipType":"testcaseOf","spdxElementId":"SPDXRef-1"},{"relatedSpdxElement":"SPDXRef-1","relationshipType":"generates","spdxElementId":"SPDXRef-3"},{"comment":"Relationship based on Maven POM file dependency information","relatedSpdxElement":"SPDXRef-8","relationshipType":"dynamicLink","spdxElementId":"SPDXRef-1"},{"comment":"Relationship based on Maven POM file dependency information","relatedSpdxElement":"SPDXRef-5","relationshipType":"testcaseOf","spdxElementId":"SPDXRef-1"},{"relatedSpdxElement":"SPDXRef-1","relationshipType":"describes","spdxElementId":"SPDXRef-DOCUMENT"}],"snippets":null,"spdxVersion":"SPDX-2.2"},"Timestamp":""}}`) fulcioURL, err := apis.ParseURL("https://fulcio.sigstore.dev") if err != nil { t.Fatalf("Failed to parse fake Fulcio URL") } tests := []struct { name string policy webhookcip.ClusterImagePolicy want *PolicyResult wantErrs []string customContext context.Context }{{ name: "simple test", policy: webhookcip.ClusterImagePolicy{ Images: []v1alpha1.ImagePattern{{ Glob: "**", }}, Authorities: []webhookcip.Authority{{ Name: "authority-0", Keyless: &webhookcip.KeylessRef{ URL: fulcioURL, Identities: []v1alpha1.Identity{{ IssuerRegExp: ".*", SubjectRegExp: ".*", }}, }, Attestations: []webhookcip.AttestationPolicy{{ Name: "test-att", PredicateType: "https://spdx.dev/Document", Type: "cue", Data: `{"predicateType": "https://spdx.dev/Document"}`, }}, }, }, }, want: &PolicyResult{ AuthorityMatches: map[string]AuthorityMatch{ "authority-0": { Attestations: map[string][]PolicyAttestation{ "test-att": {{ PolicySignature: PolicySignature{ ID: "2906bbcbb40870d95b19e1bafe1db915ae73e5cd2ae1bdfee539ab6272ae7774", Subject: "josh@dolit.ski", Issuer: "https://github.com/login/oauth", }, PredicateType: "https://spdx.dev/Document", Digest: "sha256:f764a4251b2fe3c85dd46896b9d6e65361c9683755099d6dcd13009836d2e0e4", Payload: attPayload, }}, }, }, }, }, }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { cosignVerifySignatures = cosign.VerifyImageSignatures cosignVerifyAttestations = cosign.VerifyImageAttestations testContext := context.Background() if test.customContext != nil { testContext = test.customContext } kc, err := k8schain.NewNoClient(testContext) if err != nil { t.Fatalf("Failed to construct no client k8schain for testing") } got, gotErrs := ValidatePolicy(testContext, system.Namespace(), digestAtt, test.policy, kc) validateErrors(t, test.wantErrs, gotErrs) if diff := cmp.Diff(test.want, got); diff != "" { t.Errorf("unexpected PolicyResult, %s with gotErrs %v", diff, gotErrs) } }) } } func validateErrors(t *testing.T, wantErr []string, got []error) { t.Helper() if len(wantErr) != len(got) { t.Errorf("Wanted %d errors got %d", len(wantErr), len(got)) } else { for i, want := range wantErr { if !strings.Contains(got[i].Error(), want) { t.Errorf("Unwanted error at %d want: %s got: %s", i, want, got[i]) } } } } func TestValidatePodSpecNonDefaultNamespace(t *testing.T) { tag := name.MustParseReference("gcr.io/distroless/static:nonroot") // Resolved via crane digest on 2021/09/25 digest := name.MustParseReference("gcr.io/distroless/static:nonroot@sha256:be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4") ctx, _ := rtesting.SetupFakeContext(t) // Non-existent URL for testing complete failure badURL := apis.HTTP("http://example.com/") // Spin up a Fulcio that responds with a Root Cert fulcioServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { rw.Write([]byte(fulcioRootCert)) })) t.Cleanup(fulcioServer.Close) fulcioURL, err := apis.ParseURL("https://fulcio.sigstore.dev") if err != nil { t.Fatalf("Failed to parse fake Fulcio URL") } rekorServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, _ *http.Request) { rw.Write([]byte(rekorResponse)) })) t.Cleanup(rekorServer.Close) rekorURL, err := apis.ParseURL(rekorServer.URL) if err != nil { t.Fatalf("Failed to parse fake Rekor URL") } var authorityKeyCosignPub *ecdsa.PublicKey pems := parsePems([]byte(authorityKeyCosignPubString)) if len(pems) > 0 { key, _ := x509.ParsePKIXPublicKey(pems[0].Bytes) authorityKeyCosignPub = key.(*ecdsa.PublicKey) } else { t.Errorf("Error parsing authority key from string") } kc := fakekube.Get(ctx) // Setup service acc and fakeSignaturePullSecrets for "default", "cosign-system" and "my-secure-ns" namespace for _, ns := range []string{"default", system.Namespace(), "my-secure-ns"} { kc.CoreV1().ServiceAccounts(ns).Create(ctx, &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: "default", }, }, metav1.CreateOptions{}) kc.CoreV1().Secrets(ns).Create(ctx, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: "fakeSignaturePullSecrets", }, Data: map[string][]byte{ "dockerconfigjson": []byte(`{"auths":{"https://index.docker.io/v1/":{"username":"username","password":"password","auth":"dXNlcm5hbWU6cGFzc3dvcmQ="}}`), }, }, metav1.CreateOptions{}) } // Create fake secret in a non-default namespace and patch the default service acc kc.CoreV1().Secrets("my-secure-ns").Create(ctx, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: "fakeSignaturePullSecretsNonDefault", }, Data: map[string][]byte{ "dockerconfigjson": []byte(`{"auths":{"https://index.docker.io/v1/":{"username":"username","password":"password","auth":"dXNlcm5hbWU6cGFzc3dvcmQ="}}`), }, }, metav1.CreateOptions{}) mergePatch := map[string]interface{}{ "imagePullSecrets": map[string]interface{}{ "name": "fakeSignaturePullSecretsNonDefault", }, } patch, err := json.Marshal(mergePatch) if err != nil { t.Fatalf("Failed to marshal merge patch: %v", err) } kc.CoreV1().ServiceAccounts("my-secure-ns").Patch(ctx, "default", types.MergePatchType, patch, metav1.PatchOptions{}) v := NewValidator(ctx) cvs := cosignVerifySignatures defer func() { cosignVerifySignatures = cvs }() // Let's just say that everything is verified. pass := func(_ context.Context, _ name.Reference, _ *cosign.CheckOpts) (checkedSignatures []oci.Signature, bundleVerified bool, err error) { sig, err := static.NewSignature(nil, "") if err != nil { return nil, false, err } return []oci.Signature{sig}, true, nil } // Let's just say that everything is not verified. fail := func(_ context.Context, _ name.Reference, _ *cosign.CheckOpts) (checkedSignatures []oci.Signature, bundleVerified bool, err error) { return nil, false, errors.New("bad signature") } // Let's say it is verified if it is the expected Public Key authorityPublicKeyCVS := func(ctx context.Context, signedImgRef name.Reference, co *cosign.CheckOpts) (checkedSignatures []oci.Signature, bundleVerified bool, err error) { actualPublicKey, _ := co.SigVerifier.PublicKey() actualECDSAPubkey := actualPublicKey.(*ecdsa.PublicKey) actualPubKey, err := actualECDSAPubkey.ECDH() if err != nil { return nil, false, errors.New("failed to get edch pub key") } authorityKeyPubKey, err := authorityKeyCosignPub.ECDH() if err != nil { return nil, false, errors.New("failed to get edch pub key") } if bytes.Equal(actualPubKey.Bytes(), authorityKeyPubKey.Bytes()) { return pass(ctx, signedImgRef, co) } return fail(ctx, signedImgRef, co) } tests := []struct { name string ps *corev1.PodSpec want *apis.FieldError cvs func(context.Context, name.Reference, *cosign.CheckOpts) ([]oci.Signature, bool, error) customContext context.Context }{{ name: "simple, no error", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, customContext: config.ToContext(context.Background(), &config.Config{ ImagePolicyConfig: &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{ "cluster-image-policy": { Images: []v1alpha1.ImagePattern{{ Glob: "gcr.io/*/*", }}, Authorities: []webhookcip.Authority{ { Key: &webhookcip.KeyRef{ Data: authorityKeyCosignPubString, PublicKeys: []crypto.PublicKey{authorityKeyCosignPub}, HashAlgorithm: signaturealgo.DefaultSignatureAlgorithm, HashAlgorithmCode: crypto.SHA256, }, }, }, }, }, }, }, ), cvs: pass, }, { name: "bad reference", ps: &corev1.PodSpec{ Containers: []corev1.Container{{ Name: "user-container", Image: "in@valid", }}, }, want: &apis.FieldError{ Message: `could not parse reference: in@valid`, Paths: []string{"containers[0].image"}, }, cvs: fail, }, { name: "not digest", ps: &corev1.PodSpec{ Containers: []corev1.Container{{ Name: "user-container", Image: tag.String(), }}, }, want: &apis.FieldError{ Message: `invalid value: gcr.io/distroless/static:nonroot must be an image digest`, Paths: []string{"containers[0].image"}, }, cvs: fail, }, { name: "simple, no error, authority key", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, customContext: config.ToContext(context.Background(), &config.Config{ ImagePolicyConfig: &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{ "cluster-image-policy": { Images: []v1alpha1.ImagePattern{{ Glob: "gcr.io/*/*", }}, Authorities: []webhookcip.Authority{ { Key: &webhookcip.KeyRef{ Data: authorityKeyCosignPubString, PublicKeys: []crypto.PublicKey{authorityKeyCosignPub}, HashAlgorithm: signaturealgo.DefaultSignatureAlgorithm, HashAlgorithmCode: crypto.SHA256, }, }, }, }, }, }, }, ), cvs: authorityPublicKeyCVS, }, { name: "simple, error, authority keyless, bad fulcio", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, customContext: config.ToContext(context.Background(), &config.Config{ ImagePolicyConfig: &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{ "cluster-image-policy-keyless": { Images: []v1alpha1.ImagePattern{{ Glob: "gcr.io/*/*", }}, Authorities: []webhookcip.Authority{ { Keyless: &webhookcip.KeylessRef{ URL: badURL, }, }, }, }, }, }, }, ), want: func() *apis.FieldError { var errs *apis.FieldError fe := apis.ErrGeneric("failed policy: cluster-image-policy-keyless", "image").ViaFieldIndex("containers", 0) fe.Details = fmt.Sprintf("%s %s", digest.String(), `signature keyless validation failed for authority for gcr.io/distroless/static@sha256:be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4: bad signature`) errs = errs.Also(fe) fe2 := apis.ErrGeneric("failed policy: cluster-image-policy-keyless", "image").ViaFieldIndex("initContainers", 0) fe2.Details = fe.Details errs = errs.Also(fe2) return errs }(), cvs: fail, }, { name: "simple, error, authority keyless, good fulcio, no rekor", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, customContext: config.ToContext(context.Background(), &config.Config{ ImagePolicyConfig: &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{ "cluster-image-policy-keyless": { Images: []v1alpha1.ImagePattern{{ Glob: "gcr.io/*/*", }}, Authorities: []webhookcip.Authority{ { Keyless: &webhookcip.KeylessRef{ URL: fulcioURL, }, }, }, }, }, }, }, ), want: func() *apis.FieldError { var errs *apis.FieldError fe := apis.ErrGeneric("failed policy: cluster-image-policy-keyless", "image").ViaFieldIndex("initContainers", 0) fe.Details = fmt.Sprintf("%s signature keyless validation failed for authority for %s: bad signature", digest.String(), digest.Name()) errs = errs.Also(fe) fe2 := apis.ErrGeneric("failed policy: cluster-image-policy-keyless", "image").ViaFieldIndex("containers", 0) fe2.Details = fmt.Sprintf("%s signature keyless validation failed for authority for %s: bad signature", digest.String(), digest.Name()) errs = errs.Also(fe2) return errs }(), cvs: fail, }, { name: "simple, authority keyless checks out, good fulcio, bad cip policy", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, customContext: config.ToContext(context.Background(), &config.Config{ ImagePolicyConfig: &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{ "cluster-image-policy-keyless-bad-cip": { Images: []v1alpha1.ImagePattern{{ Glob: "gcr.io/*/*", }}, Authorities: []webhookcip.Authority{ { Keyless: &webhookcip.KeylessRef{ URL: fulcioURL, }, }, }, Policy: &webhookcip.AttestationPolicy{ Name: "invalid json policy", Type: "cue", Data: `{"wontgo`, }, }, }, }, }, ), want: func() *apis.FieldError { var errs *apis.FieldError fe := apis.ErrGeneric("failed policy: cluster-image-policy-keyless-bad-cip", "image").ViaFieldIndex("initContainers", 0) fe.Details = fmt.Sprintf("%s failed evaluating cue policy for ClusterImagePolicy: failed to compile the cue policy with error: string literal not terminated", digest.String()) errs = errs.Also(fe) fe2 := apis.ErrGeneric("failed policy: cluster-image-policy-keyless-bad-cip", "image").ViaFieldIndex("containers", 0) fe2.Details = fmt.Sprintf("%s failed evaluating cue policy for ClusterImagePolicy: failed to compile the cue policy with error: string literal not terminated", digest.String()) errs = errs.Also(fe2) return errs }(), cvs: pass, }, { name: "simple, no error, authority keyless, good fulcio", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, customContext: config.ToContext(context.Background(), &config.Config{ ImagePolicyConfig: &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{ "cluster-image-policy-keyless": { Images: []v1alpha1.ImagePattern{{ Glob: "gcr.io/*/*", }}, Authorities: []webhookcip.Authority{ { Keyless: &webhookcip.KeylessRef{ URL: fulcioURL, }, }, }, }, }, }, }, ), cvs: pass, }, { name: "simple, error, authority keyless, good fulcio, bad rekor", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, customContext: config.ToContext(context.Background(), &config.Config{ ImagePolicyConfig: &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{ "cluster-image-policy-keyless": { Images: []v1alpha1.ImagePattern{{ Glob: "gcr.io/*/*", }}, Authorities: []webhookcip.Authority{ { Keyless: &webhookcip.KeylessRef{ URL: fulcioURL, }, CTLog: &v1alpha1.TLog{ URL: rekorURL, }, }, }, }, }, }, }, ), want: func() *apis.FieldError { var errs *apis.FieldError fe := apis.ErrGeneric("failed policy: cluster-image-policy-keyless", "image").ViaFieldIndex("initContainers", 0) fe.Details = fmt.Sprintf("%s signature keyless validation failed for authority for %s: bad signature", digest.String(), digest.Name()) errs = errs.Also(fe) fe2 := apis.ErrGeneric("failed policy: cluster-image-policy-keyless", "image").ViaFieldIndex("containers", 0) fe2.Details = fmt.Sprintf("%s signature keyless validation failed for authority for %s: bad signature", digest.String(), digest.Name()) errs = errs.Also(fe2) return errs }(), cvs: fail, }, { name: "simple, error, authority source signaturePullSecrets, non existing secret", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, customContext: config.ToContext(ctx, &config.Config{ ImagePolicyConfig: &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{ "cluster-image-policy": { Images: []v1alpha1.ImagePattern{{ Glob: "gcr.io/*/*", }}, Authorities: []webhookcip.Authority{ { Key: &webhookcip.KeyRef{ Data: authorityKeyCosignPubString, PublicKeys: []crypto.PublicKey{authorityKeyCosignPub}, HashAlgorithm: signaturealgo.DefaultSignatureAlgorithm, HashAlgorithmCode: crypto.SHA256, }, Sources: []v1alpha1.Source{{ OCI: "example.com/alternative/signature", SignaturePullSecrets: []corev1.LocalObjectReference{{ Name: "non-existing-secret", }}, }}, }, }, }, }, }, }, ), cvs: pass, }, { name: "simple, no error, authority source signaturePullSecrets, valid secret", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, customContext: config.ToContext(ctx, &config.Config{ ImagePolicyConfig: &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{ "cluster-image-policy": { Images: []v1alpha1.ImagePattern{{ Glob: "gcr.io/*/*", }}, Authorities: []webhookcip.Authority{ { Key: &webhookcip.KeyRef{ Data: authorityKeyCosignPubString, PublicKeys: []crypto.PublicKey{authorityKeyCosignPub}, HashAlgorithm: signaturealgo.DefaultSignatureAlgorithm, HashAlgorithmCode: crypto.SHA256, }, Sources: []v1alpha1.Source{{ OCI: "example.com/alternative/signature", SignaturePullSecrets: []corev1.LocalObjectReference{{ Name: "fakeSignaturePullSecrets", }}, }}, }, }, }, }, }, }, ), cvs: authorityPublicKeyCVS, }, { name: "simple, no error, with a resource selector based on labels and resource version", ps: &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, }, customContext: config.ToContext(context.Background(), &config.Config{ ImagePolicyConfig: &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{ "cluster-image-policy": { Images: []v1alpha1.ImagePattern{{ Glob: "gcr.io/*/*", }}, Match: []v1alpha1.MatchResource{ { GroupVersionResource: metav1.GroupVersionResource{ Group: "", Version: "v1", Resource: "pods", }, ResourceSelector: &metav1.LabelSelector{ MatchLabels: map[string]string{"test": "test"}, }, }, }, Authorities: []webhookcip.Authority{ { Key: &webhookcip.KeyRef{ Data: authorityKeyCosignPubString, PublicKeys: []crypto.PublicKey{authorityKeyCosignPub}, HashAlgorithm: signaturealgo.DefaultSignatureAlgorithm, HashAlgorithmCode: crypto.SHA256, }, }, }, }, }, }, }, ), cvs: pass, }} for _, test := range tests { t.Run(test.name, func(t *testing.T) { for _, mode := range []string{"", "enforce", "warn"} { cosignVerifySignatures = test.cvs testContext := context.Background() // By default we want errors. However, iff the mode above is // warn, and we're using a custom context and therefore // triggering the CIP.mode twiddling below, check for warnings. wantWarn := false if test.customContext != nil { if mode == "warn" { wantWarn = true } // If we are testing with custom context, loop through // all the modes here. It's a bit silly that we spin through // all the tests 3 times, but for now this is better than // duplicating all the CIPs with just different modes. testContext = test.customContext // Twiddle the mode for tests. cfg := config.FromContext(testContext) newPolicies := make(map[string]webhookcip.ClusterImagePolicy, len(cfg.ImagePolicyConfig.Policies)) for k, v := range cfg.ImagePolicyConfig.Policies { v.Mode = mode newPolicies[k] = v } cfg.ImagePolicyConfig.Policies = newPolicies config.ToContext(testContext, cfg) } // The Request body bytes are consumed in every call, so we need // to set an new request for every call attachHTTPRequestToContext := func(context.Context) context.Context { // Build fake HTTP Request admissionreq := &admissionv1.AdmissionReview{ Request: &admissionv1.AdmissionRequest{ Operation: admissionv1.Create, Kind: metav1.GroupVersionKind{ Group: "", Version: "v1", Kind: "Pod", }, Namespace: "my-secure-ns", }, } reqBuf := new(bytes.Buffer) err = json.NewEncoder(reqBuf).Encode(&admissionreq) if err != nil { t.Fatalf("Failed to marshal admission review: %v", err) } req, err := http.NewRequest("GET", "foo", reqBuf) if err != nil { t.Fatalf("NewRequest() = %v", err) } return apis.WithHTTPRequest(testContext, req) } testContext = attachHTTPRequestToContext(testContext) testContext = context.WithValue(testContext, kubeclient.Key{}, kc) // Check the core mechanics got := v.validatePodSpec(testContext, "my-secure-ns", "Pod", "v1", map[string]string{"test": "test"}, test.ps, k8schain.Options{}) if (got != nil) != (test.want != nil) { t.Errorf("validatePodSpec() = %v, wanted %v", got, test.want) } else if got != nil && got.Error() != test.want.Error() { t.Errorf("validatePodSpec() = %v, wanted %v", got, test.want) } if test.want != nil { if wantWarn { test.want.Level = apis.WarningLevel } else { test.want.Level = apis.ErrorLevel } } // Check wrapped in a Pod pod := &duckv1.Pod{ Spec: *test.ps, } testContext = attachHTTPRequestToContext(testContext) // Set the policy config to pass anything that doesn't match any // policies. testContext = policycontrollerconfig.ToContext(testContext, &policycontrollerconfig.PolicyControllerConfig{NoMatchPolicy: policycontrollerconfig.AllowAll, FailOnEmptyAuthorities: true}) got = v.ValidatePod(testContext, pod) want := test.want.ViaField("spec") if (got != nil) != (want != nil) { t.Errorf("ValidatePod() = %v, wanted %v", got, want) } else if got != nil && got.Error() != want.Error() { t.Errorf("ValidatePod() = %v, wanted %v", got, want) } // Check the warning/error level. if got != nil && test.want != nil { if got.Level != want.Level { t.Errorf("ValidatePod() Wrong Level = %v, wanted %v", got.Level, want.Level) } } // Check that we don't block things being deleted. testContext = attachHTTPRequestToContext(testContext) if got := v.ValidatePod(apis.WithinDelete(testContext), pod); got != nil { t.Errorf("ValidatePod() = %v, wanted nil", got) } // Check wrapped in a WithPod withPod := &duckv1.WithPod{ Spec: duckv1.WithPodSpec{ Template: duckv1.PodSpecable{ Spec: *test.ps, }, }, } testContext = attachHTTPRequestToContext(testContext) got = v.ValidatePodSpecable(testContext, withPod) want = test.want.ViaField("spec.template.spec") if (got != nil) != (want != nil) { t.Errorf("ValidatePodSpecable() = %v, wanted %v", got, want) } else if got != nil && got.Error() != want.Error() { t.Errorf("ValidatePodSpecable() = %v, wanted %v", got, want) } // Check the warning/error level. if got != nil && test.want != nil { if got.Level != want.Level { t.Errorf("ValidatePodSpecable() Wrong Level = %v, wanted %v", got.Level, want.Level) } } // Check that we don't block things being deleted. testContext = attachHTTPRequestToContext(testContext) if got := v.ValidatePodSpecable(apis.WithinDelete(testContext), withPod); got != nil { t.Errorf("ValidatePodSpecable() = %v, wanted nil", got) } // Check wrapped in a podScalable podScalable := &policyduckv1beta1.PodScalable{ Spec: policyduckv1beta1.PodScalableSpec{ Replicas: ptr.Int32(3), Template: corev1.PodTemplateSpec{ Spec: *test.ps, }, }, } testContext = attachHTTPRequestToContext(testContext) got = v.ValidatePodScalable(testContext, podScalable) want = test.want.ViaField("spec.template.spec") if (got != nil) != (want != nil) { t.Errorf("ValidatePodScalable() = %v, wanted %v", got, want) } else if got != nil && got.Error() != want.Error() { t.Errorf("ValidatePodScalable() = %v, wanted %v", got, want) } // Check the warning/error level. if got != nil && test.want != nil { if got.Level != want.Level { t.Errorf("ValidatePodScalable() Wrong Level = %v, wanted %v", got.Level, want.Level) } } // Check that we don't block things being deleted. testContext = attachHTTPRequestToContext(testContext) if got := v.ValidatePodScalable(apis.WithinDelete(testContext), podScalable); got != nil { t.Errorf("ValidatePodSpecable() = %v, wanted nil", got) } // Check that we don't block things being scaled down. original := podScalable.DeepCopy() original.Spec.Replicas = ptr.Int32(4) testContext = attachHTTPRequestToContext(testContext) if got := v.ValidatePodScalable(apis.WithinUpdate(testContext, original), podScalable); got != nil { t.Errorf("ValidatePodSpecable() scaling down = %v, wanted nil", got) } // Check that we fail as expected if being scaled up. original.Spec.Replicas = ptr.Int32(2) testContext = attachHTTPRequestToContext(testContext) got = v.ValidatePodScalable(apis.WithinUpdate(testContext, original), podScalable) want = test.want.ViaField("spec.template.spec") if (got != nil) != (want != nil) { t.Errorf("ValidatePodScalable() scaling up = %v, wanted %v", got, want) } else if got != nil && got.Error() != want.Error() { t.Errorf("ValidatePodScalable() scaling up = %v, wanted %v", got, want) } // Check the warning/error level. if got != nil && test.want != nil { if got.Level != want.Level { t.Errorf("ValidatePodScalable() scaling up Wrong Level = %v, wanted %v", got.Level, want.Level) } } } }) } } func TestValidatePodSpecCancelled(t *testing.T) { // Resolved via crane digest on 2021/09/25 digest := name.MustParseReference("gcr.io/distroless/static:nonroot@sha256:be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4") ctx, _ := rtesting.SetupFakeContext(t) kc := fakekube.Get(ctx) // Setup service account and fakeSignaturePullSecrets for "default" // namespace kc.CoreV1().ServiceAccounts("default").Create(ctx, &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: "default", }, }, metav1.CreateOptions{}) kc.CoreV1().Secrets("default").Create(ctx, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: "fakeSignaturePullSecrets", }, Data: map[string][]byte{ "dockerconfigjson": []byte(`{"auths":{"https://index.docker.io/v1/":{"username":"username","password":"password","auth":"dXNlcm5hbWU6cGFzc3dvcmQ="}}`), }, }, metav1.CreateOptions{}) v := NewValidator(ctx) ps := &corev1.PodSpec{ InitContainers: []corev1.Container{{ Name: "setup-stuff", Image: digest.String(), }}, Containers: []corev1.Container{{ Name: "user-container", Image: digest.String(), }}, } ctx = config.ToContext(ctx, &config.Config{ ImagePolicyConfig: &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{ "cluster-image-policy": { Images: []v1alpha1.ImagePattern{{ Glob: "gcr.io/*/*", }}, Authorities: []webhookcip.Authority{ { Keyless: &webhookcip.KeylessRef{ URL: apis.HTTP("fulcio.sigstore.dev"), }}, }, }, }, }, }) cancelledContext, cancelFunc := context.WithCancel(ctx) wantErr := "context was canceled before validation completed" cancelFunc() gotErrs := v.validatePodSpec(cancelledContext, "default", "pod", "v1", map[string]string{}, ps, k8schain.Options{}) if gotErrs == nil { t.Errorf("Did not get an error on canceled context") } else if !strings.Contains(gotErrs.Error(), wantErr) { t.Errorf("Did not get canceled error, got: %s", gotErrs.Error()) } } func TestValidatePolicyCancelled(t *testing.T) { var authorityKeyCosignPub *ecdsa.PublicKey pems := parsePems([]byte(authorityKeyCosignPubString)) if len(pems) > 0 { key, _ := x509.ParsePKIXPublicKey(pems[0].Bytes) authorityKeyCosignPub = key.(*ecdsa.PublicKey) } else { t.Errorf("Error parsing authority key from string") } // Resolved via crane digest on 2021/09/25 digest := name.MustParseReference("gcr.io/distroless/static:nonroot@sha256:be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4") testContext, cancelFunc := context.WithCancel(context.Background()) cip := webhookcip.ClusterImagePolicy{ Authorities: []webhookcip.Authority{{ Name: "authority-0", Key: &webhookcip.KeyRef{ PublicKeys: []crypto.PublicKey{authorityKeyCosignPub}, HashAlgorithm: signaturealgo.DefaultSignatureAlgorithm, HashAlgorithmCode: crypto.SHA256, }, }}, } kc, err := k8schain.NewNoClient(testContext) if err != nil { t.Fatalf("Failed to construct no client k8schain for testing") } wantErrs := []string{"context canceled before validation completed"} cancelFunc() _, gotErrs := ValidatePolicy(testContext, system.Namespace(), digest, cip, kc) validateErrors(t, wantErrs, gotErrs) } func TestValidatePoliciesCancelled(t *testing.T) { var authorityKeyCosignPub *ecdsa.PublicKey pems := parsePems([]byte(authorityKeyCosignPubString)) if len(pems) > 0 { key, _ := x509.ParsePKIXPublicKey(pems[0].Bytes) authorityKeyCosignPub = key.(*ecdsa.PublicKey) } else { t.Errorf("Error parsing authority key from string") } // Resolved via crane digest on 2021/09/25 digest := name.MustParseReference("gcr.io/distroless/static:nonroot@sha256:be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4") testContext, cancelFunc := context.WithCancel(context.Background()) cip := webhookcip.ClusterImagePolicy{ Authorities: []webhookcip.Authority{{ Name: "authority-0", Key: &webhookcip.KeyRef{ PublicKeys: []crypto.PublicKey{authorityKeyCosignPub}, HashAlgorithm: signaturealgo.DefaultSignatureAlgorithm, HashAlgorithmCode: crypto.SHA256, }, }}, } kc, err := k8schain.NewNoClient(testContext) if err != nil { t.Fatalf("Failed to construct no client k8schain for testing") } wantErrs := []string{"context was canceled before validation completed"} cancelFunc() _, gotErrs := validatePolicies(testContext, system.Namespace(), digest, map[string]webhookcip.ClusterImagePolicy{"testcip": cip}, kc) validateErrors(t, wantErrs, gotErrs["internalerror"]) } func TestPolicyControllerConfigNoMatchPolicy(t *testing.T) { digest := "gcr.io/distroless/static:nonroot@sha256:be5d77c62dbe7fedfb0a4e5ec2f91078080800ab1f18358e5f31fcc8faa023c4" testPodSpec := &corev1.PodSpec{ Containers: []corev1.Container{{ Name: "test-container", Image: digest, }}, } ctx, _ := rtesting.SetupFakeContext(t) policies := &config.ImagePolicyConfig{ Policies: map[string]webhookcip.ClusterImagePolicy{}, } ctx = config.ToContext(ctx, &config.Config{ImagePolicyConfig: policies}) v := NewValidator(ctx) // no policies kc := fakekube.Get(ctx) // Setup service acc and fakeSignaturePullSecrets for "default", "cosign-system" and "my-secure-ns" namespace for _, ns := range []string{"default", system.Namespace()} { kc.CoreV1().ServiceAccounts(ns).Create(ctx, &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ Name: "default", }, }, metav1.CreateOptions{}) kc.CoreV1().Secrets(ns).Create(ctx, &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: "fakeSignaturePullSecrets", }, Data: map[string][]byte{ "dockerconfigjson": []byte(`{"auths":{"https://index.docker.io/v1/":{"username":"username","password":"password","auth":"dXNlcm5hbWU6cGFzc3dvcmQ="}}`), }, }, metav1.CreateOptions{}) } tests := []struct { name string noMatchPolicy string want *apis.FieldError // If above should be at warning level. wantWarn bool }{{ name: "empty value - implicit deny", // this will fail because default is deny. want: func() *apis.FieldError { var errs *apis.FieldError fe := apis.ErrGeneric("no matching policies", "image").ViaFieldIndex("containers", 0) fe.Details = digest errs = errs.Also(fe) return errs }(), }, { name: "explicit deny", noMatchPolicy: "deny", want: func() *apis.FieldError { var errs *apis.FieldError fe := apis.ErrGeneric("no matching policies", "image").ViaFieldIndex("containers", 0) fe.Details = digest errs = errs.Also(fe) return errs }(), }, { name: "warn", noMatchPolicy: "warn", want: func() *apis.FieldError { var errs *apis.FieldError fe := apis.ErrGeneric("no matching policies", "image").ViaFieldIndex("containers", 0) fe.Details = digest errs = errs.Also(fe) return errs }(), }, { name: "allow", noMatchPolicy: "allow", }} for _, tc := range tests { testCtx := policycontrollerconfig.ToContext(ctx, &policycontrollerconfig.PolicyControllerConfig{NoMatchPolicy: tc.noMatchPolicy, FailOnEmptyAuthorities: true}) got := v.validatePodSpec(testCtx, system.Namespace(), "pod", "v1", map[string]string{}, testPodSpec, k8schain.Options{}) if (got != nil) != (tc.want != nil) { t.Errorf("ValidatePodSpecable() = %v, wanted %v", got, tc.want) } else if got != nil && got.Error() != tc.want.Error() { t.Errorf("ValidatePodSpecable() = %v, wanted %v", got, tc.want) } if tc.want != nil && tc.wantWarn { tc.want.Level = apis.WarningLevel } // Check the warning/error level. if got != nil && tc.want != nil { if got.Level != tc.want.Level { t.Errorf("ValidatePod() Wrong Level = %v, wanted %v", got.Level, tc.want.Level) } } } } func TestFulcioCertsFromAuthority(t *testing.T) { certs, err := cryptoutils.UnmarshalCertificatesFromPEM([]byte(certChain)) if err != nil { t.Fatalf("Failed to unmarshal certs for testing: %v", err) } roots := x509.NewCertPool() // last cert is the root roots.AddCert(certs[2]) intermediates := x509.NewCertPool() intermediates.AddCert(certs[0]) intermediates.AddCert(certs[1]) embeddedRoots, err := fulcioroots.Get() if err != nil { t.Fatalf("Failed to get embedded fulcioroots for testing") } embeddedIntermediates, err := fulcioroots.GetIntermediates() if err != nil { t.Fatalf("Failed to get embedded fulcioroots for testing") } embeddedCTLogKeys, err := cosign.GetCTLogPubs(context.Background()) if err != nil { t.Fatalf("Failed to get embedded CTLog Public keys for testing") } pbpk, marshalledPK, err := config.DeserializePublicKey([]byte(ctfePublicKey)) if err != nil { t.Fatalf("Failed to deserialize CTLog public key: %v", err) } certChain, err := config.DeserializeCertChain([]byte(certChain)) if err != nil { t.Fatalf("Failed to deserialize cert chain: %v", err) } sk := config.SigstoreKeys{ CertificateAuthorities: []*config.CertificateAuthority{{ Subject: &config.DistinguishedName{ Organization: "testorg", CommonName: "testcommonname", }, CertChain: certChain, }}, Ctlogs: []*config.TransparencyLogInstance{{ LogId: &config.LogID{KeyId: []byte(ctfeLogID)}, PublicKey: pbpk, }}, } c := &config.Config{ SigstoreKeysConfig: &config.SigstoreKeysMap{ SigstoreKeys: map[string]*config.SigstoreKeys{ "test-trust-root": &sk, }, }, } testCtx := config.ToContext(context.Background(), c) tests := []struct { name string keylessRef *webhookcip.KeylessRef wantErr string wantRoots *x509.CertPool wantIntermediates *x509.CertPool wantCTLogKeys *cosign.TrustedTransparencyLogPubKeys ctx context.Context }{{ name: "no trustroots, uses embedded", keylessRef: &webhookcip.KeylessRef{}, wantRoots: embeddedRoots, wantIntermediates: embeddedIntermediates, wantCTLogKeys: embeddedCTLogKeys, }, { name: "config does not exist", keylessRef: &webhookcip.KeylessRef{TrustRootRef: "not-there"}, wantErr: "getting SigstoreKeys: trustRootRef not-there not found, config missing", ctx: config.ToContext(context.Background(), nil), }, { name: "SigstoreKeys does not exist", keylessRef: &webhookcip.KeylessRef{TrustRootRef: "not-there"}, wantErr: "getting SigstoreKeys: trustRootRef not-there not found, SigstoreKeys missing", ctx: config.ToContext(context.Background(), &config.Config{}), }, { name: "trustroot does not exist", keylessRef: &webhookcip.KeylessRef{TrustRootRef: "not-there"}, ctx: testCtx, wantErr: "trustRootRef not-there not found", }, { name: "trustroot found", keylessRef: &webhookcip.KeylessRef{TrustRootRef: "test-trust-root"}, ctx: testCtx, wantRoots: roots, wantIntermediates: intermediates, wantCTLogKeys: &cosign.TrustedTransparencyLogPubKeys{Keys: map[string]cosign.TransparencyLogPubKey{ctfeLogID: {PubKey: marshalledPK, Status: tuf.Active}}}, }} for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { tCtx := tc.ctx if tCtx == nil { tCtx = context.Background() } roots, intermediates, ctlogKeys, err := fulcioCertsFromAuthority(tCtx, tc.keylessRef) if err != nil { if tc.wantErr == "" { t.Errorf("unexpected error: %v wanted none", err) } else if err.Error() != tc.wantErr { t.Errorf("unexpected error: %v wanted %q", err, tc.wantErr) } } else if tc.wantErr != "" { t.Errorf("wanted error: %q got none", tc.wantErr) } if !roots.Equal(tc.wantRoots) { t.Errorf("Roots differ") } if !intermediates.Equal(tc.wantIntermediates) { t.Errorf("Intermediates differ") } if diff := cmp.Diff(tc.wantCTLogKeys, ctlogKeys); diff != "" { t.Errorf("CTLog keys differ: %s", diff) } }) } } func TestRekorClientAndKeysFromAuthority(t *testing.T) { pbpk, pk, err := config.DeserializePublicKey([]byte(rekorPublicKey)) if err != nil { t.Fatalf("Failed to unmarshal public key for testing: %v", err) } ecpk, ok := pk.(*ecdsa.PublicKey) if !ok { t.Fatalf("pk is not a ecsda public key") } embeddedPKs, err := cosign.GetRekorPubs(context.Background()) if err != nil { t.Fatalf("Failed to get embedded rekor pubs for testing") } if len(embeddedPKs.Keys) != 1 { t.Fatalf("Did not get a single Public Key for Rekor") } var embeddedLogID string var embeddedPK crypto.PublicKey for k, v := range embeddedPKs.Keys { embeddedLogID = k embeddedPK = v.PubKey } sk := config.SigstoreKeys{ Tlogs: []*config.TransparencyLogInstance{{ PublicKey: pbpk, LogId: &config.LogID{KeyId: []byte(rekorLogID)}, BaseUrl: "rekor.example.com", }}, } c := &config.Config{ SigstoreKeysConfig: &config.SigstoreKeysMap{ SigstoreKeys: map[string]*config.SigstoreKeys{ "test-trust-root": &sk, }, }, } testCtx := config.ToContext(context.Background(), c) tests := []struct { name string tlog *v1alpha1.TLog wantErr string wantPK crypto.PublicKey wantLogID string wantClient bool ctx context.Context }{{ name: "no trustroots, uses embedded", tlog: &v1alpha1.TLog{URL: apis.HTTPS("rekor.sigstore.dev")}, wantPK: embeddedPK, wantLogID: embeddedLogID, wantClient: true, }, { name: "config does not exist", tlog: &v1alpha1.TLog{TrustRootRef: "not-there"}, wantErr: "fetching keys for trustRootRef: getting SigstoreKeys: trustRootRef not-there not found, config missing", ctx: config.ToContext(context.Background(), nil), }, { name: "SigstoreKeys does not exist", tlog: &v1alpha1.TLog{TrustRootRef: "not-there"}, wantErr: "fetching keys for trustRootRef: getting SigstoreKeys: trustRootRef not-there not found, SigstoreKeys missing", ctx: config.ToContext(context.Background(), &config.Config{}), }, { name: "trustroot does not exist", tlog: &v1alpha1.TLog{TrustRootRef: "not-there"}, ctx: testCtx, wantErr: "fetching keys for trustRootRef: trustRootRef not-there not found", }, { name: "trustroot found", tlog: &v1alpha1.TLog{TrustRootRef: "test-trust-root"}, wantPK: ecpk, wantLogID: rekorLogID, ctx: testCtx, wantClient: true, }} for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { tCtx := tc.ctx if tCtx == nil { tCtx = context.Background() } rekorClient, gotPKs, err := rekorClientAndKeysFromAuthority(tCtx, webhookcip.Authority{CTLog: tc.tlog}) if err != nil { if tc.wantErr == "" { t.Errorf("unexpected error: %v wanted none", err) } else if err.Error() != tc.wantErr { t.Errorf("unexpected error: %v wanted %q", err, tc.wantErr) } } else if tc.wantErr != "" { t.Errorf("wanted error: %q got none", tc.wantErr) } if tc.wantLogID != "" { if gotPKs == nil || gotPKs.Keys == nil { t.Errorf("Wanted logid %s got none", tc.wantLogID) } else if diff := cmp.Diff(gotPKs.Keys[tc.wantLogID].PubKey, tc.wantPK); diff != "" { t.Errorf("did not get wanted PK: %s", diff) } } else if gotPKs != nil { t.Errorf("did not want PK, %+v", gotPKs) } if tc.wantClient && rekorClient == nil { t.Errorf("wanted rekor client, but got none") } else if !tc.wantClient && rekorClient != nil { t.Errorf("did not want rekor client, but got one") } }) } } func TestCheckOptsFromAuthority(t *testing.T) { pbpkRekor, pkRekor, err := config.DeserializePublicKey([]byte(rekorPublicKey)) if err != nil { t.Fatalf("Failed to unmarshal public key for testing: %v", err) } pbpkCTFE, pkCTFE, err := config.DeserializePublicKey([]byte(ctfePublicKey)) if err != nil { t.Fatalf("Failed to unmarshal public key for testing: %v", err) } ecpk, ok := pkRekor.(*ecdsa.PublicKey) if !ok { t.Fatalf("pk is not a ecsda public key") } embeddedPKs, err := cosign.GetRekorPubs(context.Background()) if err != nil { t.Fatalf("Failed to get embedded rekor pubs for testing") } if len(embeddedPKs.Keys) != 1 { t.Fatalf("Did not get a single Public Key for Rekor") } var embeddedLogID string var embeddedPK crypto.PublicKey for k, v := range embeddedPKs.Keys { embeddedLogID = k embeddedPK = v.PubKey } certs, err := cryptoutils.UnmarshalCertificatesFromPEM([]byte(certChain)) if err != nil { t.Fatalf("Failed to unmarshal certs for testing: %v", err) } roots := x509.NewCertPool() // last cert is the root roots.AddCert(certs[2]) intermediates := x509.NewCertPool() intermediates.AddCert(certs[0]) intermediates.AddCert(certs[1]) embeddedRoots, err := fulcioroots.Get() if err != nil { t.Fatalf("Failed to get embedded fulcioroots for testing") } embeddedIntermediates, err := fulcioroots.GetIntermediates() if err != nil { t.Fatalf("Failed to get embedded fulcioroots for testing") } embeddedCTLogKeys, err := cosign.GetCTLogPubs(context.Background()) if err != nil { t.Fatalf("Failed to get embedded CTLog Public keys for testing") } skRekor := config.SigstoreKeys{ Tlogs: []*config.TransparencyLogInstance{{ PublicKey: pbpkRekor, LogId: &config.LogID{KeyId: []byte("rekor-logid")}, BaseUrl: "rekor.example.com", }}, } certChainPB, err := config.DeserializeCertChain([]byte(certChain)) if err != nil { t.Fatalf("Failed to unmarshal cert chain for testing: %v", err) } skFulcio := config.SigstoreKeys{ CertificateAuthorities: []*config.CertificateAuthority{{ Subject: &config.DistinguishedName{ Organization: "testorg", CommonName: "testcommonname", }, CertChain: certChainPB, }}, Ctlogs: []*config.TransparencyLogInstance{{ LogId: &config.LogID{KeyId: []byte(ctfeLogID)}, PublicKey: pbpkCTFE, }}, } skCombined := config.SigstoreKeys{ MediaType: "application/vnd.dev.sigstore.trustedroot+json;version=0.1", Tlogs: []*config.TransparencyLogInstance{{ PublicKey: pbpkRekor, LogId: &config.LogID{KeyId: []byte("rekor-logid")}, BaseUrl: "rekor.example.com", HashAlgorithm: pbcommon.HashAlgorithm_SHA2_256, }}, CertificateAuthorities: []*config.CertificateAuthority{{ Subject: &config.DistinguishedName{ Organization: "testorg", CommonName: "testcommonname", }, CertChain: certChainPB, }}, Ctlogs: []*config.TransparencyLogInstance{{ LogId: &config.LogID{KeyId: []byte(ctfeLogID)}, PublicKey: pbpkCTFE, HashAlgorithm: pbcommon.HashAlgorithm_SHA2_256, }}, } c := &config.Config{ SigstoreKeysConfig: &config.SigstoreKeysMap{ SigstoreKeys: map[string]*config.SigstoreKeys{ "test-trust-rekor": &skRekor, "test-trust-fulcio": &skFulcio, "test-trust-combined": &skCombined, }, }, } testCtx := config.ToContext(context.Background(), c) tests := []struct { name string authority webhookcip.Authority wantErr string wantCheckOpts *cosign.CheckOpts ctx context.Context wantClient bool }{{ name: "no trustroots, uses embedded", authority: webhookcip.Authority{ CTLog: &v1alpha1.TLog{URL: apis.HTTPS("rekor.sigstore.dev")}, Keyless: &webhookcip.KeylessRef{URL: apis.HTTPS("fulcio.sigstore.dev")}, }, wantCheckOpts: &cosign.CheckOpts{ RekorPubKeys: &cosign.TrustedTransparencyLogPubKeys{Keys: map[string]cosign.TransparencyLogPubKey{embeddedLogID: {PubKey: embeddedPK, Status: tuf.Active}}}, RootCerts: embeddedRoots, IntermediateCerts: embeddedIntermediates, CTLogPubKeys: embeddedCTLogKeys, }, wantClient: true, }, { name: "SigstoreKeys does not exist for Rekor", authority: webhookcip.Authority{ Name: "test-authority", CTLog: &v1alpha1.TLog{ URL: apis.HTTPS("rekor.example.com"), TrustRootRef: "not-there"}}, wantErr: "getting Rekor public keys: test-authority: fetching keys for trustRootRef: trustRootRef not-there not found", ctx: testCtx, }, { name: "SigstoreKeys does not exist for Fulcio", authority: webhookcip.Authority{ Name: "test-authority", Keyless: &webhookcip.KeylessRef{ URL: apis.HTTPS("fulcio.example.com"), TrustRootRef: "not-there"}}, wantErr: "getting Fulcio certs: test-authority: trustRootRef not-there not found", ctx: testCtx, }, { name: "trustroot found, Rekor", authority: webhookcip.Authority{ CTLog: &v1alpha1.TLog{ URL: apis.HTTPS("rekor.example.com"), TrustRootRef: "test-trust-rekor"}}, ctx: testCtx, wantClient: true, wantCheckOpts: &cosign.CheckOpts{ RekorPubKeys: &cosign.TrustedTransparencyLogPubKeys{Keys: map[string]cosign.TransparencyLogPubKey{"rekor-logid": {PubKey: ecpk, Status: tuf.Active}}}, }, }, { name: "trustroot found, Fulcio", authority: webhookcip.Authority{ Keyless: &webhookcip.KeylessRef{ URL: apis.HTTPS("fulcio.example.com"), TrustRootRef: "test-trust-fulcio"}}, ctx: testCtx, wantCheckOpts: &cosign.CheckOpts{ RootCerts: roots, IntermediateCerts: intermediates, IgnoreTlog: true, CTLogPubKeys: &cosign.TrustedTransparencyLogPubKeys{Keys: map[string]cosign.TransparencyLogPubKey{ctfeLogID: {PubKey: pkCTFE, Status: tuf.Active}}}, }, }, { name: "trustroot found, combined, with Identities", authority: webhookcip.Authority{ CTLog: &v1alpha1.TLog{ URL: apis.HTTPS("rekor.example.com"), TrustRootRef: "test-trust-rekor"}, Keyless: &webhookcip.KeylessRef{ Identities: []v1alpha1.Identity{{ Issuer: "issuer", Subject: "subject", }}, URL: apis.HTTPS("rekor.example.com"), TrustRootRef: "test-trust-combined"}}, ctx: testCtx, wantClient: true, wantCheckOpts: &cosign.CheckOpts{ RootCerts: roots, IntermediateCerts: intermediates, RekorPubKeys: &cosign.TrustedTransparencyLogPubKeys{Keys: map[string]cosign.TransparencyLogPubKey{"rekor-logid": {PubKey: ecpk, Status: tuf.Active}}}, Identities: []cosign.Identity{{ Issuer: "issuer", Subject: "subject", }}, CTLogPubKeys: &cosign.TrustedTransparencyLogPubKeys{Keys: map[string]cosign.TransparencyLogPubKey{ctfeLogID: {PubKey: pkCTFE, Status: tuf.Active}}}, }, }, { name: "bundle format, with Identities and Rekor", authority: webhookcip.Authority{ SignatureFormat: "bundle", CTLog: &v1alpha1.TLog{ URL: apis.HTTPS("rekor.example.com"), TrustRootRef: "test-trust-combined", }, Keyless: &webhookcip.KeylessRef{ TrustRootRef: "test-trust-combined", Identities: []v1alpha1.Identity{{ Issuer: "issuer", Subject: "subject", }}, }, }, ctx: testCtx, wantCheckOpts: &cosign.CheckOpts{ NewBundleFormat: true, Identities: []cosign.Identity{{ Issuer: "issuer", Subject: "subject", }}, TrustedMaterial: &root.TrustedRoot{}, }, }, { name: "bundle format, with TSA", authority: webhookcip.Authority{ SignatureFormat: "bundle", // Test keys do not contain a TSA but that is okay as we are just constructing the checkOpts RFC3161Timestamp: &webhookcip.RFC3161Timestamp{ TrustRootRef: "test-trust-combined", }, Keyless: &webhookcip.KeylessRef{ TrustRootRef: "test-trust-combined", }, }, ctx: testCtx, wantCheckOpts: &cosign.CheckOpts{ NewBundleFormat: true, UseSignedTimestamps: true, TrustedMaterial: &root.TrustedRoot{}, IgnoreTlog: true, }, }, { name: "bundle format, bad TrustRootRef", authority: webhookcip.Authority{ SignatureFormat: "bundle", Keyless: &webhookcip.KeylessRef{ TrustRootRef: "not-there", }, }, ctx: testCtx, wantErr: "trustRootRef not-there not found", }, { name: "bundle format, unsupported different trustroots", authority: webhookcip.Authority{ SignatureFormat: "bundle", CTLog: &v1alpha1.TLog{ TrustRootRef: "test-trust-rekor", }, Keyless: &webhookcip.KeylessRef{ TrustRootRef: "test-trust-combined", }, }, ctx: testCtx, wantErr: "when using the new bundle format, the trustRootRef for the TLog must be the same as the trustRootRef for the Keyless authority", }, { name: "bundle format, unsupported non-keyless", authority: webhookcip.Authority{ SignatureFormat: "bundle", }, ctx: testCtx, wantErr: "when using the new bundle format, the authority must be keyless", }} for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { tCtx := tc.ctx if tCtx == nil { tCtx = context.Background() } gotCheckOpts, err := checkOptsFromAuthority(tCtx, tc.authority) if err != nil { if tc.wantErr == "" { t.Errorf("unexpected error: %v wanted none", err) } else if err.Error() != tc.wantErr { t.Errorf("unexpected error: %v wanted %q", err, tc.wantErr) } } else if tc.wantErr != "" { t.Errorf("wanted error: %q got none", tc.wantErr) } if tc.wantClient && (gotCheckOpts == nil || gotCheckOpts.RekorClient == nil) { t.Errorf("wanted rekor client, but got none") } else if !tc.wantClient && gotCheckOpts != nil && gotCheckOpts.RekorClient != nil { t.Errorf("did not want rekor client, but got one") } // nil out the rekorclient since we can't meaningfully diff it, and // we check above that we get one when we expect one, and don't when // we don't. if gotCheckOpts != nil { gotCheckOpts.RekorClient = nil } if diff := cmp.Diff(gotCheckOpts, tc.wantCheckOpts, cmpopts.IgnoreUnexported(root.TrustedRoot{})); diff != "" { t.Errorf("CheckOpts differ: %s", diff) } }) } } func TestSignatureID(t *testing.T) { cert := mustRead(t, "testdata/cert.pem") for _, tc := range []struct { name string sig oci.Signature want string }{ { name: "no cert", sig: newStaticSig(t, []byte("foo"), nil), want: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", }, { name: "with cert", sig: newStaticSig(t, []byte("foo"), cert), want: "0b413181a61e85e0426d9f49ccd58d2205314297ee0c3bb515ad9d0f89480995", }, } { got, err := signatureID(tc.sig) if err != nil { t.Fatal(err) } if tc.want != got { t.Errorf("want %s, got %s", tc.want, got) } } } func mustRead(t *testing.T, path string) []byte { t.Helper() b, err := os.ReadFile(path) if err != nil { t.Fatal(err) } return b } func newStaticSig(t *testing.T, payload []byte, cert []byte) oci.Signature { t.Helper() var opts []static.Option if cert != nil { opts = append(opts, static.WithCertChain(cert, nil)) } out, err := static.NewSignature(payload, "", opts...) if err != nil { t.Fatal(err) } return out } // TODO: This test needs a more realistic DSSE envelope mock func TestValidAttestationsOCI11Enabled_DISABLED(t *testing.T) { t.Skip("Skipping until DSSE envelope mocking is improved") ctx := context.Background() ref := name.MustParseReference("example.com/test@sha256:abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234") checkOpts := &cosign.CheckOpts{} // Save originals origResolve := ociremoteResolveDigest origReferrers := ociremoteReferrers origVerifyAtt := cosignVerifyAttestations defer func() { ociremoteResolveDigest = origResolve ociremoteReferrers = origReferrers cosignVerifyAttestations = origVerifyAtt }() // Test with EnableOCI11 = true cfg := &policycontrollerconfig.PolicyControllerConfig{ EnableOCI11: true, } ctx = policycontrollerconfig.ToContext(ctx, cfg) // Mock successful OCI 1.1 discovery ociremoteResolveDigest = func(ref name.Reference, opts ...remote.Option) (name.Digest, error) { return name.MustParseReference("example.com/test@sha256:abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234").(name.Digest), nil } mockManifest := &v1.IndexManifest{ Manifests: []v1.Descriptor{ { ArtifactType: "application/vnd.in-toto+json", Digest: v1.Hash{ Algorithm: "sha256", Hex: "attestationdigest", }, }, }, } ociremoteReferrers = func(d name.Digest, artifactType string, opts ...remote.Option) (*v1.IndexManifest, error) { return mockManifest, nil } // Create a mock signed image with DSSE envelope dsseContent := []byte(`{"payload":"eyJmb28iOiJiYXIifQ==","signatures":[{"sig":"c2lnbmF0dXJl"}]}`) ociremoteSignedImage = func(ref name.Reference, opts ...remote.Option) (oci.SignedImage, error) { return &mockSignedImage{ layers: []v1.Layer{ &mockLayer{content: dsseContent}, }, }, nil } // Should call OCI 1.1 path, not legacy legacyCalled := false cosignVerifyAttestations = func(ctx context.Context, ref name.Reference, co *cosign.CheckOpts, nameOpts ...name.Option) ([]oci.Signature, bool, error) { legacyCalled = true return nil, false, errors.New("should not call legacy") } _, err := validAttestations(ctx, ref, checkOpts) // OCI 1.1 should succeed and legacy should not be called if legacyCalled { t.Error("Legacy cosignVerifyAttestations should not have been called when OCI 1.1 succeeds") } if err != nil { t.Errorf("Expected OCI 1.1 to succeed, got error: %v", err) } } func TestValidAttestationsOCI11Fallback(t *testing.T) { ctx := context.Background() ref := name.MustParseReference("example.com/test@sha256:abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234") checkOpts := &cosign.CheckOpts{} // Save originals origResolve := ociremoteResolveDigest origVerifyAtt := cosignVerifyAttestations defer func() { ociremoteResolveDigest = origResolve cosignVerifyAttestations = origVerifyAtt }() // Test with EnableOCI11 = true but OCI 1.1 fails cfg := &policycontrollerconfig.PolicyControllerConfig{ EnableOCI11: true, } ctx = policycontrollerconfig.ToContext(ctx, cfg) // Mock OCI 1.1 to fail ociremoteResolveDigest = func(ref name.Reference, opts ...remote.Option) (name.Digest, error) { return name.Digest{}, errors.New("OCI 1.1 not supported") } // Mock legacy to succeed legacyCalled := false mockSig, _ := static.NewSignature(nil, "") cosignVerifyAttestations = func(ctx context.Context, ref name.Reference, co *cosign.CheckOpts, nameOpts ...name.Option) ([]oci.Signature, bool, error) { legacyCalled = true return []oci.Signature{mockSig}, true, nil } sigs, err := validAttestations(ctx, ref, checkOpts) if !legacyCalled { t.Error("Legacy cosignVerifyAttestations should have been called as fallback") } if err != nil { t.Errorf("Expected fallback to succeed, got error: %v", err) } if len(sigs) != 1 { t.Errorf("Expected 1 signature from fallback, got %d", len(sigs)) } } func TestValidAttestationsOCI11Disabled(t *testing.T) { ctx := context.Background() ref := name.MustParseReference("example.com/test@sha256:abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234") checkOpts := &cosign.CheckOpts{} // Save originals origResolve := ociremoteResolveDigest origVerifyAtt := cosignVerifyAttestations defer func() { ociremoteResolveDigest = origResolve cosignVerifyAttestations = origVerifyAtt }() // Test with EnableOCI11 = false (default) cfg := &policycontrollerconfig.PolicyControllerConfig{ EnableOCI11: false, } ctx = policycontrollerconfig.ToContext(ctx, cfg) // Mock OCI 1.1 - should not be called oci11Called := false ociremoteResolveDigest = func(ref name.Reference, opts ...remote.Option) (name.Digest, error) { oci11Called = true return name.Digest{}, errors.New("should not call") } // Mock legacy to succeed mockSig, _ := static.NewSignature(nil, "") cosignVerifyAttestations = func(ctx context.Context, ref name.Reference, co *cosign.CheckOpts, nameOpts ...name.Option) ([]oci.Signature, bool, error) { return []oci.Signature{mockSig}, true, nil } sigs, err := validAttestations(ctx, ref, checkOpts) if oci11Called { t.Error("OCI 1.1 path should not have been called when disabled") } if err != nil { t.Errorf("Expected legacy to succeed, got error: %v", err) } if len(sigs) != 1 { t.Errorf("Expected 1 signature, got %d", len(sigs)) } } func TestDiscoverAttestationsOCI11NoAttestations(t *testing.T) { ctx := context.Background() ref := name.MustParseReference("example.com/test@sha256:abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234") checkOpts := &cosign.CheckOpts{} // Save originals origResolve := ociremoteResolveDigest origReferrers := ociremoteReferrers defer func() { ociremoteResolveDigest = origResolve ociremoteReferrers = origReferrers }() ociremoteResolveDigest = func(ref name.Reference, opts ...remote.Option) (name.Digest, error) { return name.MustParseReference("example.com/test@sha256:abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234").(name.Digest), nil } // Return index with no in-toto artifacts mockManifest := &v1.IndexManifest{ Manifests: []v1.Descriptor{ { ArtifactType: "application/vnd.oci.image.manifest.v1+json", Digest: v1.Hash{ Algorithm: "sha256", Hex: "somedigest", }, }, }, } ociremoteReferrers = func(d name.Digest, artifactType string, opts ...remote.Option) (*v1.IndexManifest, error) { return mockManifest, nil } _, err := discoverAttestationsOCI11(ctx, ref, checkOpts) if err == nil { t.Error("Expected error when no attestations found") } if !strings.Contains(err.Error(), "no attestations found") { t.Errorf("Expected 'no attestations found' error, got: %v", err) } } func TestDiscoverAttestationsOCI11ResolveDigestFails(t *testing.T) { ctx := context.Background() ref := name.MustParseReference("example.com/test@sha256:abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234") checkOpts := &cosign.CheckOpts{} // Save original origResolve := ociremoteResolveDigest defer func() { ociremoteResolveDigest = origResolve }() ociremoteResolveDigest = func(ref name.Reference, opts ...remote.Option) (name.Digest, error) { return name.Digest{}, errors.New("resolve failed") } _, err := discoverAttestationsOCI11(ctx, ref, checkOpts) if err == nil { t.Error("Expected error when resolve digest fails") } if !strings.Contains(err.Error(), "resolve failed") { t.Errorf("Expected 'resolve failed' error, got: %v", err) } } func TestDiscoverAttestationsOCI11ReferrersFails(t *testing.T) { ctx := context.Background() ref := name.MustParseReference("example.com/test@sha256:abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234") checkOpts := &cosign.CheckOpts{} // Save originals origResolve := ociremoteResolveDigest origReferrers := ociremoteReferrers defer func() { ociremoteResolveDigest = origResolve ociremoteReferrers = origReferrers }() ociremoteResolveDigest = func(ref name.Reference, opts ...remote.Option) (name.Digest, error) { return name.MustParseReference("example.com/test@sha256:abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234").(name.Digest), nil } ociremoteReferrers = func(d name.Digest, artifactType string, opts ...remote.Option) (*v1.IndexManifest, error) { return nil, errors.New("referrers API not supported") } _, err := discoverAttestationsOCI11(ctx, ref, checkOpts) if err == nil { t.Error("Expected error when referrers call fails") } if !strings.Contains(err.Error(), "referrers API not supported") { t.Errorf("Expected 'referrers API not supported' error, got: %v", err) } } // Mock types for testing type mockSignedImage struct { layers []v1.Layer } func (m *mockSignedImage) Digest() (v1.Hash, error) { return v1.Hash{}, nil } func (m *mockSignedImage) Signatures() (oci.Signatures, error) { return nil, nil } func (m *mockSignedImage) Attestations() (oci.Signatures, error) { return nil, nil } func (m *mockSignedImage) Attachment(name string) (oci.File, error) { return nil, nil } func (m *mockSignedImage) Layers() ([]v1.Layer, error) { return m.layers, nil } func (m *mockSignedImage) ConfigName() (v1.Hash, error) { return v1.Hash{}, nil } func (m *mockSignedImage) ConfigFile() (*v1.ConfigFile, error) { return nil, nil } func (m *mockSignedImage) RawConfigFile() ([]byte, error) { return nil, nil } func (m *mockSignedImage) Manifest() (*v1.Manifest, error) { return nil, nil } func (m *mockSignedImage) RawManifest() ([]byte, error) { return nil, nil } func (m *mockSignedImage) LayerByDigest(hash v1.Hash) (v1.Layer, error) { return nil, nil } func (m *mockSignedImage) LayerByDiffID(hash v1.Hash) (v1.Layer, error) { return nil, nil } func (m *mockSignedImage) MediaType() (v1types.MediaType, error) { return v1types.OCIManifestSchema1, nil } func (m *mockSignedImage) Size() (int64, error) { return 0, nil } type mockLayer struct { content []byte } func (m *mockLayer) Digest() (v1.Hash, error) { return v1.Hash{}, nil } func (m *mockLayer) DiffID() (v1.Hash, error) { return v1.Hash{}, nil } func (m *mockLayer) Compressed() (io.ReadCloser, error) { return io.NopCloser(bytes.NewReader(m.content)), nil } func (m *mockLayer) Uncompressed() (io.ReadCloser, error) { return io.NopCloser(bytes.NewReader(m.content)), nil } func (m *mockLayer) Size() (int64, error) { return int64(len(m.content)), nil } func (m *mockLayer) MediaType() (v1types.MediaType, error) { return v1types.OCILayer, nil } func TestProcessAttestationArtifact(t *testing.T) { // Save original origSignedImage := ociremoteSignedImage defer func() { ociremoteSignedImage = origSignedImage }() repo, _ := name.NewRepository("example.com/test") descriptor := v1.Descriptor{ Digest: v1.Hash{ Algorithm: "sha256", Hex: "abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234", }, } tests := []struct { name string descriptor v1.Descriptor mockImage func(name.Reference, ...remote.Option) (oci.SignedImage, error) wantErr bool wantSigCount int }{ { name: "valid DSSE envelope", descriptor: descriptor, mockImage: func(ref name.Reference, opts ...remote.Option) (oci.SignedImage, error) { // Valid DSSE envelope with proper base64 payload dsseContent := []byte(`{"payload":"eyJ0ZXN0IjoidmFsdWUifQ==","signatures":[{"sig":"c2lnbmF0dXJl"}]}`) return &mockSignedImage{ layers: []v1.Layer{ &mockLayer{content: dsseContent}, }, }, nil }, wantErr: false, wantSigCount: 1, }, { name: "multiple signatures in envelope", descriptor: descriptor, mockImage: func(ref name.Reference, opts ...remote.Option) (oci.SignedImage, error) { dsseContent := []byte(`{"payload":"eyJ0ZXN0IjoidmFsdWUifQ==","signatures":[{"sig":"c2lnMQ=="},{"sig":"c2lnMg=="}]}`) return &mockSignedImage{ layers: []v1.Layer{ &mockLayer{content: dsseContent}, }, }, nil }, wantErr: false, wantSigCount: 2, }, { name: "invalid digest format", descriptor: v1.Descriptor{ Digest: v1.Hash{ Algorithm: "sha256", Hex: "invalid", }, }, mockImage: func(ref name.Reference, opts ...remote.Option) (oci.SignedImage, error) { return nil, nil }, wantErr: true, }, { name: "failed to get signed image", descriptor: descriptor, mockImage: func(ref name.Reference, opts ...remote.Option) (oci.SignedImage, error) { return nil, errors.New("failed to fetch image") }, wantErr: true, }, { name: "no layers in image", descriptor: descriptor, mockImage: func(ref name.Reference, opts ...remote.Option) (oci.SignedImage, error) { return &mockSignedImage{ layers: []v1.Layer{}, }, nil }, wantErr: true, }, { name: "invalid JSON in layer", descriptor: descriptor, mockImage: func(ref name.Reference, opts ...remote.Option) (oci.SignedImage, error) { return &mockSignedImage{ layers: []v1.Layer{ &mockLayer{content: []byte("not json")}, }, }, nil }, wantErr: true, }, { name: "empty signatures array", descriptor: descriptor, mockImage: func(ref name.Reference, opts ...remote.Option) (oci.SignedImage, error) { dsseContent := []byte(`{"payload":"eyJ0ZXN0IjoidmFsdWUifQ==","signatures":[]}`) return &mockSignedImage{ layers: []v1.Layer{ &mockLayer{content: dsseContent}, }, }, nil }, wantErr: false, wantSigCount: 0, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ociremoteSignedImage = tt.mockImage sigs, err := processAttestationArtifact(tt.descriptor, repo, nil) if (err != nil) != tt.wantErr { t.Errorf("wantErr=%v, got err=%v", tt.wantErr, err) } if !tt.wantErr && len(sigs) != tt.wantSigCount { t.Errorf("wanted %d signatures, got %d", tt.wantSigCount, len(sigs)) } }) } } func TestDiscoverAttestationsOCI11SuccessfulDiscovery(t *testing.T) { ctx := context.Background() ref := name.MustParseReference("example.com/test@sha256:abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234") checkOpts := &cosign.CheckOpts{} // Save originals origResolve := ociremoteResolveDigest origReferrers := ociremoteReferrers origProcessAtt := testProcessAttestationArtifact defer func() { ociremoteResolveDigest = origResolve ociremoteReferrers = origReferrers testProcessAttestationArtifact = origProcessAtt }() ociremoteResolveDigest = func(ref name.Reference, opts ...remote.Option) (name.Digest, error) { return name.MustParseReference("example.com/test@sha256:abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234").(name.Digest), nil } // Return manifest with in-toto attestations mockManifest := &v1.IndexManifest{ Manifests: []v1.Descriptor{ { ArtifactType: "application/vnd.in-toto+json", Digest: v1.Hash{ Algorithm: "sha256", Hex: "att1111111111111111111111111111111111111111111111111111111111", }, }, { ArtifactType: "application/vnd.in-toto.provenance", Digest: v1.Hash{ Algorithm: "sha256", Hex: "att2222222222222222222222222222222222222222222222222222222222", }, }, }, } ociremoteReferrers = func(d name.Digest, artifactType string, opts ...remote.Option) (*v1.IndexManifest, error) { return mockManifest, nil } // Mock processAttestationArtifact to return valid signatures testProcessAttestationArtifact = func(result v1.Descriptor, repository name.Repository, registryOpts []remote.Option) ([]oci.Signature, error) { mockSig, _ := static.NewSignature(nil, "") return []oci.Signature{mockSig}, nil } sigs, err := discoverAttestationsOCI11(ctx, ref, checkOpts) if err != nil { t.Errorf("Expected success, got error: %v", err) } // Should have 2 signatures (one from each in-toto artifact) if len(sigs) != 2 { t.Errorf("Expected 2 signatures from 2 in-toto artifacts, got %d", len(sigs)) } } func TestDiscoverAttestationsOCI11MixedArtifacts(t *testing.T) { ctx := context.Background() ref := name.MustParseReference("example.com/test@sha256:abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234") checkOpts := &cosign.CheckOpts{} // Save originals origResolve := ociremoteResolveDigest origReferrers := ociremoteReferrers origProcessAtt := testProcessAttestationArtifact defer func() { ociremoteResolveDigest = origResolve ociremoteReferrers = origReferrers testProcessAttestationArtifact = origProcessAtt }() ociremoteResolveDigest = func(ref name.Reference, opts ...remote.Option) (name.Digest, error) { return name.MustParseReference("example.com/test@sha256:abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234").(name.Digest), nil } // Mix of in-toto and non-in-toto artifacts (should only process in-toto) mockManifest := &v1.IndexManifest{ Manifests: []v1.Descriptor{ { ArtifactType: "application/vnd.oci.image.manifest.v1+json", Digest: v1.Hash{ Algorithm: "sha256", Hex: "img1111111111111111111111111111111111111111111111111111111111", }, }, { ArtifactType: "application/vnd.in-toto+dsse", Digest: v1.Hash{ Algorithm: "sha256", Hex: "att1111111111111111111111111111111111111111111111111111111111", }, }, { ArtifactType: "application/vnd.oci.artifact.manifest.v1+json", Digest: v1.Hash{ Algorithm: "sha256", Hex: "art1111111111111111111111111111111111111111111111111111111111", }, }, }, } ociremoteReferrers = func(d name.Digest, artifactType string, opts ...remote.Option) (*v1.IndexManifest, error) { return mockManifest, nil } processedCount := 0 testProcessAttestationArtifact = func(result v1.Descriptor, repository name.Repository, registryOpts []remote.Option) ([]oci.Signature, error) { processedCount++ mockSig, _ := static.NewSignature(nil, "") return []oci.Signature{mockSig}, nil } sigs, err := discoverAttestationsOCI11(ctx, ref, checkOpts) if err != nil { t.Errorf("Expected success, got error: %v", err) } // Should only process the one in-toto artifact if processedCount != 1 { t.Errorf("Expected processAttestationArtifact to be called once, called %d times", processedCount) } if len(sigs) != 1 { t.Errorf("Expected 1 signature from 1 in-toto artifact, got %d", len(sigs)) } } func TestDiscoverAttestationsOCI11PartialProcessingFailure(t *testing.T) { ctx := context.Background() ref := name.MustParseReference("example.com/test@sha256:abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234") checkOpts := &cosign.CheckOpts{} // Save originals origResolve := ociremoteResolveDigest origReferrers := ociremoteReferrers origProcessAtt := testProcessAttestationArtifact defer func() { ociremoteResolveDigest = origResolve ociremoteReferrers = origReferrers testProcessAttestationArtifact = origProcessAtt }() ociremoteResolveDigest = func(ref name.Reference, opts ...remote.Option) (name.Digest, error) { return name.MustParseReference("example.com/test@sha256:abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234abcd1234").(name.Digest), nil } // Multiple in-toto artifacts mockManifest := &v1.IndexManifest{ Manifests: []v1.Descriptor{ { ArtifactType: "application/vnd.in-toto+json", Digest: v1.Hash{ Algorithm: "sha256", Hex: "good111111111111111111111111111111111111111111111111111111111", }, }, { ArtifactType: "application/vnd.in-toto+json", Digest: v1.Hash{ Algorithm: "sha256", Hex: "bad2222222222222222222222222222222222222222222222222222222222", }, }, { ArtifactType: "application/vnd.in-toto+json", Digest: v1.Hash{ Algorithm: "sha256", Hex: "good333333333333333333333333333333333333333333333333333333333", }, }, }, } ociremoteReferrers = func(d name.Digest, artifactType string, opts ...remote.Option) (*v1.IndexManifest, error) { return mockManifest, nil } callCount := 0 testProcessAttestationArtifact = func(result v1.Descriptor, repository name.Repository, registryOpts []remote.Option) ([]oci.Signature, error) { callCount++ if callCount == 2 { // Second call fails return nil, errors.New("processing failed for second artifact") } // First and third succeed mockSig, _ := static.NewSignature(nil, "") return []oci.Signature{mockSig}, nil } sigs, err := discoverAttestationsOCI11(ctx, ref, checkOpts) // Should succeed with 2 signatures (second one failed but was skipped with logging) if err != nil { t.Errorf("Expected success with partial failures, got error: %v", err) } if callCount != 3 { t.Errorf("Expected processAttestationArtifact called 3 times, got %d", callCount) } if len(sigs) != 2 { t.Errorf("Expected 2 signatures (second failed), got %d", len(sigs)) } } ================================================ FILE: release/README.md ================================================ # Release This directory contain the files and scripts to run a policy-controller release. # Cutting a Policy Controller Release 1. Release notes: Create a PR to update and review release notes in CHANGELOG.md. - Check merged pull requests since the last release and make sure enhancements, bug fixes, and authors are reflected in the notes. You can get a list of pull requests since the last release by substituting in the date of the last release and running: ``` git log --pretty="* %s" --after="YYYY-MM-DD" ``` and a list of authors by running: ``` git log --pretty="* %an" --after="YYYY-MM-DD" | sort -u ``` 2. Tag the repository ```shell $ export RELEASE_TAG= $ git tag -s ${RELEASE_TAG} -m "${RELEASE_TAG}" $ git push origin ${RELEASE_TAG} ``` 3. The tag push will start the https://github.com/sigstore/policy-controller/blob/main/.github/workflows/release.yaml job and will build and release all the artifacts and images. 4. Send an announcement email to `sigstore-dev@googlegroups.com` mailing list 5. Tweet about the new release with a fun new trigonometry pun! 6. Honk! #### After the release: * Add a pending new section in CHANGELOG.md to set up for the next release ================================================ FILE: release/ko-sign-release-images.sh ================================================ #!/usr/bin/env bash # 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. set -o errexit set -o nounset set -o pipefail : "${GIT_HASH:?Environment variable empty or not defined.}" : "${GIT_VERSION:?Environment variable empty or not defined.}" if [[ ! -f policyControllerImagerefs ]]; then echo "policyControllerImagerefs not found" exit 1 fi echo "Signing images with Keyless..." cosign sign --yes -a GIT_HASH="$GIT_HASH" -a GIT_VERSION="$GIT_VERSION" $(cat policyControllerImagerefs) ================================================ FILE: release/ldflags.sh ================================================ #!/usr/bin/env bash # 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. set -o errexit set -o nounset set -o pipefail # Output LDFlAGS for a given environment. LDFLAGS are applied to all go binary # builds. # # Args: env function ldflags() { local GIT_VERSION=$(git describe --tags --always --dirty) local GIT_COMMIT=$(git rev-parse HEAD) local GIT_TREESTATE="clean" if [[ $(git diff --stat) != '' ]]; then GIT_TREESTATE="dirty" fi local DATE_FMT="+%Y-%m-%dT%H:%M:%SZ" local BUILD_DATE=$(date "$DATE_FMT") local SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) if [ $SOURCE_DATE_EPOCH ] then local BUILD_DATE=$(date -u -d "@$SOURCE_DATE_EPOCH" "$DATE_FMT" 2>/dev/null || date -u -r "$SOURCE_DATE_EPOCH" "$DATE_FMT" 2>/dev/null || date -u "$DATE_FMT") fi echo "-buildid= -X sigs.k8s.io/release-utils/version.gitVersion=$GIT_VERSION \ -X sigs.k8s.io/release-utils/version.gitCommit=$GIT_COMMIT \ -X sigs.k8s.io/release-utils/version.gitTreeState=$GIT_TREESTATE \ -X sigs.k8s.io/release-utils/version.buildDate=$BUILD_DATE" } ================================================ FILE: release/release.mk ================================================ ###################### # sign section ###################### .PHONY: build-sign-release-images build-sign-release-images: ko GIT_HASH=$(GIT_HASH) GIT_VERSION=$(GIT_VERSION) \ ./release/ko-sign-release-images.sh #################### # copy image to GHCR #################### .PHONY: copy-policy-controller-signed-release-to-ghcr copy-policy-controller-signed-release-to-ghcr: cosign copy $(KO_PREFIX)/policy-controller:$(GIT_VERSION) $(GHCR_PREFIX)/policy-controller:$(GIT_VERSION) .PHONY: copy-signed-release-to-ghcr copy-signed-release-to-ghcr: copy-policy-controller-signed-release-to-ghcr ================================================ FILE: test/cert_utils.go ================================================ // 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. package test import ( "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "math/big" "net" "net/url" "time" ) /* To use: rootCert, rootKey, _ := GenerateRootCa() subCert, subKey, _ := GenerateSubordinateCa(rootCert, rootKey) leafCert, _, _ := GenerateLeafCert("subject", "oidc-issuer", subCert, subKey) roots := x509.NewCertPool() subs := x509.NewCertPool() roots.AddCert(rootCert) subs.AddCert(subCert) opts := x509.VerifyOptions{ Roots: roots, Intermediates: subs, KeyUsages: []x509.ExtKeyUsage{ x509.ExtKeyUsageCodeSigning, }, } _, err := leafCert.Verify(opts) */ func createCertificate(template *x509.Certificate, parent *x509.Certificate, pub interface{}, priv crypto.Signer) (*x509.Certificate, error) { certBytes, err := x509.CreateCertificate(rand.Reader, template, parent, pub, priv) if err != nil { return nil, err } cert, err := x509.ParseCertificate(certBytes) if err != nil { return nil, err } return cert, nil } func GenerateRootCa() (*x509.Certificate, *ecdsa.PrivateKey, error) { rootTemplate := &x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{ CommonName: "sigstore", Organization: []string{"sigstore.dev"}, }, NotBefore: time.Now().Add(-5 * time.Minute), NotAfter: time.Now().Add(5 * time.Hour), KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, BasicConstraintsValid: true, IsCA: true, } priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return nil, nil, err } cert, err := createCertificate(rootTemplate, rootTemplate, &priv.PublicKey, priv) if err != nil { return nil, nil, err } return cert, priv, nil } func GenerateSubordinateCa(rootTemplate *x509.Certificate, rootPriv crypto.Signer) (*x509.Certificate, *ecdsa.PrivateKey, error) { subTemplate := &x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{ CommonName: "sigstore-sub", Organization: []string{"sigstore.dev"}, }, NotBefore: time.Now().Add(-2 * time.Minute), NotAfter: time.Now().Add(2 * time.Hour), KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning}, BasicConstraintsValid: true, IsCA: true, } priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return nil, nil, err } cert, err := createCertificate(subTemplate, rootTemplate, &priv.PublicKey, rootPriv) if err != nil { return nil, nil, err } return cert, priv, nil } func GenerateLeafCert(subject string, oidcIssuer string, parentTemplate *x509.Certificate, parentPriv crypto.Signer) (*x509.Certificate, *ecdsa.PrivateKey, error) { certTemplate := &x509.Certificate{ SerialNumber: big.NewInt(1), EmailAddresses: []string{subject}, NotBefore: time.Now().Add(-1 * time.Minute), NotAfter: time.Now().Add(time.Hour), KeyUsage: x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning}, IsCA: false, ExtraExtensions: []pkix.Extension{{ // OID for OIDC Issuer extension Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 1}, Critical: false, Value: []byte(oidcIssuer), }}, } priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return nil, nil, err } cert, err := createCertificate(certTemplate, parentTemplate, &priv.PublicKey, parentPriv) if err != nil { return nil, nil, err } return cert, priv, nil } func GenerateLeafCertWithSubjectAlternateNames(dnsNames []string, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL, oidcIssuer string, parentTemplate *x509.Certificate, parentPriv crypto.Signer) (*x509.Certificate, *ecdsa.PrivateKey, error) { certTemplate := &x509.Certificate{ SerialNumber: big.NewInt(1), EmailAddresses: emailAddresses, DNSNames: dnsNames, IPAddresses: ipAddresses, URIs: uris, NotBefore: time.Now().Add(-1 * time.Minute), NotAfter: time.Now().Add(time.Hour), KeyUsage: x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning}, IsCA: false, ExtraExtensions: []pkix.Extension{{ // OID for OIDC Issuer extension Id: asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 57264, 1, 1}, Critical: false, Value: []byte(oidcIssuer), }}, } priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return nil, nil, err } cert, err := createCertificate(certTemplate, parentTemplate, &priv.PublicKey, parentPriv) if err != nil { return nil, nil, err } return cert, priv, nil } ================================================ FILE: test/ci.mk ================================================ ############ # signing ci ############ .PHONY: sign-policy-images sign-policy-images: cosign sign -a GIT_HASH=$(GIT_HASH) ${KO_PREFIX}/policy-controller:$(GIT_HASH) .PHONY: build-sign-containers build-sign-containers: ko sign-policy-images ================================================ FILE: test/cmd/getoidctoken/main.go ================================================ // 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. package main import ( "fmt" "log" "net/http" "os" "time" "github.com/kelseyhightower/envconfig" ) type envConfig struct { FileName string `envconfig:"OIDC_FILE" default:"/var/run/sigstore/policy-controller/oidc-token" required:"true"` } func tokenWriter(filename string) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, req *http.Request) { getToken(filename, w, req) } } func getToken(tokenFile string, w http.ResponseWriter, _ *http.Request) { content, err := os.ReadFile(tokenFile) if err != nil { log.Print("failed to read token file", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } _, err = fmt.Fprint(w, string(content)) if err != nil { log.Print("failed to write token file to response", err) http.Error(w, err.Error(), http.StatusInternalServerError) } } func main() { var env envConfig if err := envconfig.Process("", &env); err != nil { log.Fatalf("failed to process env var: %s", err) } http.HandleFunc("/", tokenWriter(env.FileName)) server := &http.Server{ Addr: ":8080", ReadHeaderTimeout: 5 * time.Second, } if err := server.ListenAndServe(); err != nil { panic(err) } } ================================================ FILE: test/config/gettoken/gettoken.yaml ================================================ # 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 # # https://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. apiVersion: serving.knative.dev/v1 kind: Service metadata: name: gettoken spec: template: spec: containers: - name: gettoken image: ko://github.com/sigstore/policy-controller/test/cmd/getoidctoken env: - name: OIDC_FILE value: "/var/run/sigstore/cosign/oidc-token" volumeMounts: - name: oidc-info mountPath: /var/run/sigstore/cosign volumes: - name: oidc-info projected: sources: - serviceAccountToken: path: oidc-token expirationSeconds: 600 audience: sigstore ================================================ FILE: test/e2e_test_cluster_image_policy.sh ================================================ #!/usr/bin/env bash # # 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. set -ex if [[ -z "${OIDC_TOKEN}" ]]; then if [[ -z "${ISSUER_URL}" ]]; then echo "Must specify either env variable OIDC_TOKEN or ISSUER_URL" exit 1 else export OIDC_TOKEN=`curl -s ${ISSUER_URL}` fi fi if [[ -z "${KO_DOCKER_REPO}" ]]; then echo "Must specify env variable KO_DOCKER_REPO" exit 1 fi if [[ -z "${FULCIO_URL}" ]]; then echo "Must specify env variable FULCIO_URL" exit 1 fi if [[ -z "${REKOR_URL}" ]]; then echo "Must specify env variable REKOR_URL" exit 1 fi if [[ -z "${TUF_ROOT_FILE}" ]]; then echo "must specify env variable TUF_ROOT_FILE" exit 1 fi if [[ -z "${TUF_MIRROR}" ]]; then echo "must specify env variable TUF_MIRROR" exit 1 fi if [[ "${NON_REPRODUCIBLE}"=="1" ]]; then echo "creating non-reproducible build by adding a timestamp" export TIMESTAMP=`date +%s` else export TIMESTAMP="TIMESTAMP" fi # Initialize cosign with our TUF root cosign initialize --mirror ${TUF_MIRROR} --root ${TUF_ROOT_FILE} # To simplify testing failures, use this function to execute a kubectl to create # our job and verify that the failure is expected. assert_error() { local KUBECTL_OUT_FILE="/tmp/kubectl.failure.out" match="$@" echo looking for ${match} kubectl delete job job-that-fails -n ${NS} --ignore-not-found=true if kubectl create -n ${NS} job job-that-fails --image=${demoimage} 2> ${KUBECTL_OUT_FILE} ; then echo Failed to block expected Job failure! exit 1 else echo Successfully blocked Job creation with expected error: "${match}" if ! grep -q "${match}" ${KUBECTL_OUT_FILE} ; then echo Did not get expected failure message, wanted "${match}", got cat ${KUBECTL_OUT_FILE} exit 1 fi fi } # Publish the first test image echo '::group:: publish test image demoimage' pushd $(mktemp -d) go mod init example.com/demo cat < main.go package main import "fmt" func main() { fmt.Println("hello world TIMESTAMP") } EOF sed -i'' -e "s@TIMESTAMP@${TIMESTAMP}@g" main.go cat main.go export demoimage=`ko publish -B example.com/demo` echo Created image $demoimage popd echo '::endgroup::' # Publish the second test image echo '::group:: publish test image demoimage' pushd $(mktemp -d) go mod init example.com/demo cat < main.go package main import "fmt" func main() { fmt.Println("hello world 2 TIMESTAMP") } EOF sed -i'' -e "s@TIMESTAMP@${TIMESTAMP}@g" main.go cat main.go export demoimage2=`ko publish -B example.com/demo` popd echo '::endgroup::' echo '::group:: Deploy ClusterImagePolicy with keyless signing' kubectl apply -f ./test/testdata/policy-controller/e2e/cip-keyless.yaml echo '::endgroup::' echo '::group:: Sign demo image' if ! cosign sign --rekor-url ${REKOR_URL} --fulcio-url ${FULCIO_URL} --yes --allow-insecure-registry ${demoimage} --identity-token ${OIDC_TOKEN} ; then echo "failed to sign with keyless" exit 1 fi echo '::endgroup::' echo '::group:: Verify demo image' if ! cosign verify --rekor-url ${REKOR_URL} --allow-insecure-registry --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage} ; then echo "failed to verify with keyless" fi echo '::endgroup::' echo '::group:: Create test namespace and label for verification' kubectl create namespace demo-keyless-signing kubectl label namespace demo-keyless-signing policy.sigstore.dev/include=true export NS=demo-keyless-signing echo '::endgroup::' echo '::group:: test job success' # We signed this above, this should work if ! kubectl create -n demo-keyless-signing job demo --image=${demoimage} ; then echo Failed to create Job in namespace with matching signature! exit 1 else echo Succcessfully created Job with signed image fi echo '::endgroup::' # Create a CIP with static fail, since they are ANDed together, even though it # passed above will now fail. echo '::group:: Create CIP that always fails' kubectl apply -f ./test/testdata/policy-controller/e2e/cip-static-fail.yaml # allow things to propagate sleep 5 echo '::endgroup::' echo '::group:: test with static fail' expected_error='disallowed by static policy' assert_error ${expected_error} echo '::endgroup::' echo '::group:: Create CIP that always passes' kubectl apply -f ./test/testdata/policy-controller/e2e/cip-static-pass.yaml # allow things to propagate sleep 5 echo '::endgroup::' echo '::group:: test with static fail and static pass' expected_error='disallowed by static policy' assert_error ${expected_error} echo '::endgroup::' echo '::group:: Delete CIP that always fails' kubectl delete cip image-policy-static-fail # allow things to propagate sleep 5 echo '::endgroup::' echo '::group:: test with static pass should work' # We signed this above, and there's pass always so should work if ! kubectl create -n demo-keyless-signing job demo-works --image=${demoimage} ; then echo Failed to create Job in namespace with matching signature and static pass! exit 1 else echo Succcessfully created Job with signed image and static pass fi echo '::endgroup::' # We did not sign this, should fail echo '::group:: test job rejection' if kubectl create -n demo-keyless-signing job demo2 --image=${demoimage2} ; then echo Failed to block unsigned Job creation! exit 1 else echo Successfully blocked Job creation with unsigned image fi echo '::endgroup::' echo '::group:: Add cip with identities that match issuer/subject' kubectl apply -f ./test/testdata/policy-controller/e2e/cip-keyless-with-identities.yaml # make sure the reconciler has enough time to update the configmap sleep 5 echo '::endgroup::' # This has correct issuer/subject, so should work echo '::group:: test job success with identities' if ! kubectl create -n demo-keyless-signing job demo-identities-works --image=${demoimage} ; then echo Failed to create Job in namespace with matching issuer/subject! exit 1 else echo Succcessfully created Job with signed image keyless fi echo '::endgroup::' echo '::group:: Add cip with identities that do not match issuer/subject' kubectl apply -f ./test/testdata/policy-controller/e2e/cip-keyless-with-identities-mismatch.yaml # make sure the reconciler has enough time to update the configmap sleep 5 echo '::endgroup::' echo '::group:: test job block with mismatching issuer/subject' expected_error='none of the expected identities matched what was in the certificate' assert_error ${expected_error} echo '::endgroup::' echo '::group:: Remove mismatching cip, start fresh for key' kubectl delete cip --all echo 'done deleting cips' sleep 5 echo '::endgroup::' echo '::group:: Generate New Signing Key For Colocated Signature' COSIGN_PASSWORD="" cosign generate-key-pair mv cosign.key cosign-colocated-signing.key mv cosign.pub cosign-colocated-signing.pub echo '::endgroup::' echo '::group:: Deploy ClusterImagePolicy With Key Signing' yq '. | .spec.authorities[0].key.data |= load_str("cosign-colocated-signing.pub")' \ ./test/testdata/policy-controller/e2e/cip-key.yaml | \ kubectl apply -f - echo '::endgroup::' echo '::group:: Create and label new namespace for verification' kubectl create namespace demo-key-signing kubectl label namespace demo-key-signing policy.sigstore.dev/include=true echo '::group:: Verify blocks unsigned with the key' if kubectl create -n demo-key-signing job demo --image=${demoimage}; then echo Failed to block unsigned Job creation! exit 1 fi echo '::endgroup::' echo '::group:: Sign demoimage with cosign key' if ! COSIGN_PASSWORD="" cosign sign --key cosign-colocated-signing.key --yes --allow-insecure-registry --rekor-url ${REKOR_URL} ${demoimage} ; then echo failed to sign demoimage with key exit 1 fi echo '::endgroup::' echo '::group:: Verify demoimage with cosign key' if ! cosign verify --key cosign-colocated-signing.pub --allow-insecure-registry --rekor-url ${REKOR_URL} --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage} ; then echo failed to verify demo image with cosign key exit 1 fi echo '::endgroup::' echo '::group:: test job success' # We signed this above, this should work if ! kubectl create -n demo-key-signing job demo --image=${demoimage} ; then echo Failed to create Job in namespace after signing with key! exit 1 else echo Succcessfully created Job with signed image fi echo '::endgroup::' # Deploy a CIP that adds a keyless entry, that tests OR. echo '::group:: Deploy ClusterImagePolicy With Key Signing' yq '. | .spec.authorities[0].key.data |= load_str("cosign-colocated-signing.pub")' \ ./test/testdata/policy-controller/e2e/cip-key-and-keyless.yaml | \ kubectl apply -f - # Give the policy controller a moment to update the configmap # and pick up the change in the admission controller. sleep 5 echo '::endgroup::' echo '::group:: test with key and keyless, authorities OR' if ! kubectl create -n demo-key-signing job demo-with-or --image=${demoimage} ; then echo Failed to create Job in namespace after adding a keyless authority, OR is not working exit 1 else echo Succcessfully created Job with signed image fi echo '::endgroup::' echo '::group:: test job rejection' # We did not sign this, should fail if kubectl create -n demo-key-signing job demo2 --image=${demoimage2} ; then echo Failed to block unsigned Job creation! exit 1 else echo Successfully blocked Job creation with unsigned image fi echo '::endgroup::' # Deploy a CIP that adds a keyless entry, that tests OR. echo '::group:: Deploy ClusterImagePolicy With Key Signing and Ignore SCT' yq '. | .spec.authorities[0].key.data |= load_str("cosign-colocated-signing.pub")' \ ./test/testdata/policy-controller/e2e/cip-key-and-keyless-ignore-sct.yaml | \ kubectl apply -f - # Give the policy controller a moment to update the configmap # and pick up the change in the admission controller. sleep 5 echo '::endgroup::' echo '::group:: test with key and keyless ignoring sct' if ! kubectl create -n demo-key-signing job demo-ignore-sct --image=${demoimage} ; then echo Failed to create Job in namespace after adding a keyless authority ignoring sct, OR is not working exit 1 else echo Succcessfully created Job with signed image fi echo '::endgroup::' echo '::group:: test job rejection ignoring sct' # We did not sign this, should fail if kubectl create -n demo-key-signing job demo2-ignore-sct --image=${demoimage2} ; then echo Failed to block unsigned Job creation! exit 1 else echo Successfully blocked Job creation with unsigned image fi echo '::endgroup::' echo '::group:: Generate new Signing key and secret used for validating secret' COSIGN_PASSWORD="" cosign generate-key-pair mv cosign.key cosign-secret.key mv cosign.pub cosign-secret.pub kubectl -n cosign-system create secret generic cip-secret --from-file=secret=./cosign-secret.pub echo '::endgroup::' echo '::group:: Deploy ClusterImagePolicy with secret as the key' kubectl apply -f ./test/testdata/policy-controller/e2e/cip-key-secret.yaml # Give the policy controller a moment to update the configmap # and pick up the change in the admission controller. sleep 5 echo '::endgroup::' echo '::group:: test with key and keyless, authorities OR' if kubectl create -n demo-key-signing job demo-with-secret --image=${demoimage} ; then echo Failed to block Job in namespace after adding a secretRef exit 1 else echo Succcessfully blocked Job with secretRef key but not signed with it. fi echo '::endgroup::' echo '::group:: Sign demoimage with cosign key secret' if ! COSIGN_PASSWORD="" cosign sign --key cosign-secret.key --yes --allow-insecure-registry --rekor-url ${REKOR_URL} ${demoimage} ; then echo failed to sign demoimage with key secret exit 1 fi echo '::endgroup::' echo '::group:: Verify demoimage with cosign key secret' if ! cosign verify --key cosign-secret.pub --allow-insecure-registry --rekor-url ${REKOR_URL} --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage} ; then echo failed to verify demo image with cosign key exit 1 fi echo '::endgroup::' echo '::group:: test with secret signed' if ! kubectl create -n demo-key-signing job demo-with-secret --image=${demoimage} ; then echo Failed to create Job in namespace after signing with secretRef exit 1 else echo Succcessfully created Job with secretRef signed. fi echo '::endgroup::' echo '::group:: Generate New Signing Key For Remote Signature' COSIGN_PASSWORD="" cosign generate-key-pair mv cosign.key cosign-remote-signing.key mv cosign.pub cosign-remote-signing.pub echo '::endgroup::' echo '::group:: Deploy ClusterImagePolicy With Remote Public Key But Missing Source' yq '. | .metadata.name = "image-policy-remote-source" | .spec.authorities[0].key.data |= load_str("cosign-remote-signing.pub")' \ ./test/testdata/policy-controller/e2e/cip-key.yaml | \ kubectl apply -f - # Give the policy controller a moment to update the configmap # and pick up the change in the admission controller. sleep 5 echo '::endgroup::' echo '::group:: Sign demoimage with cosign remote key' if ! COSIGN_PASSWORD="" COSIGN_REPOSITORY="${KO_DOCKER_REPO}/remote-signature" cosign sign --key cosign-remote-signing.key --yes --allow-insecure-registry --rekor-url ${REKOR_URL} ${demoimage} ; then echo "failed to sign with remote key" exit 1 fi echo '::endgroup::' echo '::group:: Verify demoimage with cosign remote key' if cosign verify --key cosign-remote-signing.pub --allow-insecure-registry --rekor-url ${REKOR_URL} --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage}; then echo "Signature should not have been verified unless COSIGN_REPOSITORY was defined" exit 1 fi if ! COSIGN_REPOSITORY="${KO_DOCKER_REPO}/remote-signature" cosign verify --key cosign-remote-signing.pub --allow-insecure-registry --rekor-url ${REKOR_URL} --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage}; then echo "Signature should have been verified when COSIGN_REPOSITORY was defined" exit 1 fi echo '::endgroup::' echo '::group:: Create test namespace and label for remote key verification' kubectl create namespace demo-key-remote kubectl label namespace demo-key-remote policy.sigstore.dev/include=true echo '::endgroup::' echo '::group:: Verify with three CIP, one without correct Source set' if kubectl create -n demo-key-remote job demo --image=${demoimage}; then echo Failed to block unsigned Job creation! exit 1 fi echo '::endgroup::' echo '::group:: Deploy ClusterImagePolicy With Remote Public Key With Source' yq '. | .metadata.name = "image-policy-remote-source" | .spec.authorities[0].key.data |= load_str("cosign-remote-signing.pub") | .spec.authorities[0] += {"source": [{"oci": env(KO_DOCKER_REPO)+"/remote-signature"}]}' \ ./test/testdata/policy-controller/e2e/cip-key.yaml | \ kubectl apply -f - # Give the policy controller a moment to update the configmap # and pick up the change in the admission controller. sleep 5 echo '::endgroup::' echo '::group:: Verify with three CIP, one with correct Source set' # We signed this above and applied remote signature source location above if ! kubectl create -n demo-key-remote job demo --image=${demoimage}; then echo Failed to create Job with Remote Public Key with Source exit 1 else echo Succcessfully created Job with signed image fi echo '::endgroup::' echo '::group::' Cleanup kubectl delete cip --all kubectl delete ns demo-key-signing demo-keyless-signing demo-key-remote rm cosign*.key cosign*.pub echo '::endgroup::' echo '::group:: Generate New Signing Key For Matching Resources with Labels' COSIGN_PASSWORD="" cosign generate-key-pair mv cosign.key cosign-match-signing.key mv cosign.pub cosign-match-signing.pub echo '::endgroup::' echo '::group:: Create test namespace and label for matching Pods only in namespace' kubectl create namespace demo-match-res-label-only kubectl label namespace demo-match-res-label-only policy.sigstore.dev/include=true echo '::endgroup::' echo '::group:: Deploy ClusterImagePolicy With Matching Resource Labels for Pods' yq '. | .metadata.name = "image-policy-match-label" | .spec.authorities[0].key.data |= load_str("cosign-match-signing.pub")' \ ./test/testdata/policy-controller/e2e/cip-match-resource-label.yaml | \ kubectl apply -f - # Give the policy controller a moment to update the configmap # and pick up the change in the admission controller. sleep 5 echo '::endgroup::' # For pods that do not match labels, meaning there are no matching policies, we # need to flip the default behaviour of deny => allow. # But, let's flip it here before the tests to make sure matched pods are # denied properly. echo '::group:: Change no-match policy to warn' kubectl patch configmap/config-policy-controller \ --namespace cosign-system \ --type merge \ --patch '{"data":{"no-match-policy":"allow"}}' # allow for propagation sleep 5 echo '::endgroup::' echo '::group:: Verify with CIP that blocks a pod with valid labels but a different key' if kubectl run -n demo-match-res-label-only demo-invalid-key --image=${demoimage} -l match=match; then echo Failed to block signed Pod with wrong key creation! exit 1 fi echo '::endgroup::' echo '::group:: Verify with CIP that pods can get deployed due to unmatching labels' if ! kubectl run -n demo-match-res-label-only demo-valid-key --image=${demoimage} -l test=staging; then echo Failed to create Pod when labels are not matching the CIP exit 1 else echo Succcessfully created Pod when labels are not matching the CIP fi echo '::endgroup::' echo '::group:: Sign demoimage with cosign key' if ! COSIGN_PASSWORD="" cosign sign --key cosign-match-signing.key --yes --allow-insecure-registry --rekor-url ${REKOR_URL} ${demoimage} ; then echo failed to sign demoimage with key exit 1 fi echo '::endgroup::' echo '::group:: Verify demoimage with cosign key' if ! cosign verify --key cosign-match-signing.pub --allow-insecure-registry --rekor-url ${REKOR_URL} --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage} ; then echo failed to verify demo image with cosign key exit 1 fi echo '::endgroup::' echo '::group:: Verify with CIP that blocks the pod using a valid key and labels' if ! kubectl run -n demo-match-res-label-only demo-valid-key-labels --image=${demoimage} -l match=match; then echo Failed to create Pod with a valid key and matching labels exit 1 else echo Succcessfully created Pod with a valid key and matching labels fi echo '::endgroup::' echo '::group::' Cleanup kubectl delete cip --all kubectl delete ns demo-match-res-label-only rm cosign*.key cosign*.pub echo '::endgroup::' demoimageSignature="quay.io/jetstack/cert-manager-acmesolver:v1.9.1" echo '::group:: Create test namespace and label for signature digest sha512' kubectl create namespace demo-key-sha512 kubectl label namespace demo-key-sha512 policy.sigstore.dev/include=true echo '::endgroup::' echo '::group:: Deploy ClusterImagePolicy With signature digest sha512' yq '. | .metadata.name = "image-policy-sha512-key"' \ ./test/testdata/policy-controller/e2e/cip-key-hash-algorithm.yaml | \ kubectl apply -f - echo '::endgroup::' echo '::group:: Verify ClusterImagePolicy With signature digest sha512 using a pod' # We use a signed image provided by jetstack for cert-manager-acmesolver:v1.9.1 if ! kubectl run -n demo-key-sha512 job demo-sha512-key --image=${demoimageSignature}; then echo Failed to create Pod with signature digest sha512 exit 1 else echo Succcessfully created Pod with signature digest sha512 fi echo '::endgroup::' echo '::group::' Cleanup kubectl delete cip --all kubectl delete ns demo-key-sha512 echo '::endgroup::' # These tests have been running for awhile now, so grab a new OIDC_TOKEN since # we've seen them expire in the middle of the tests. export OIDC_TOKEN=`curl -s ${ISSUER_URL}` # Publish the first test image echo '::group:: publish test image demoEphemeralImage' pushd $(mktemp -d) go mod init example.com/demo cat < main.go package main import ( "fmt" "time" ) func main() { // Calling Sleep method time.Sleep(8 * time.Minute) fmt.Println("Sleep Over.....") } EOF sed -i'' -e "s@TIMESTAMP@${TIMESTAMP}@g" main.go cat main.go export demoEphemeralImage=`ko publish -B example.com/demo` echo Created image $demoEphemeralImage popd echo '::endgroup::' echo '::group:: Deploy ClusterImagePolicy with keyless signing' kubectl apply -f ./test/testdata/policy-controller/e2e/cip-keyless.yaml echo '::endgroup::' echo '::group:: Sign demo image' if ! cosign sign --rekor-url ${REKOR_URL} --fulcio-url ${FULCIO_URL} --yes --allow-insecure-registry ${demoEphemeralImage} --identity-token ${OIDC_TOKEN} ; then echo "failed to sign with keyless" exit 1 fi echo '::endgroup::' echo '::group:: Verify demo image' if ! cosign verify --rekor-url ${REKOR_URL} --allow-insecure-registry --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoEphemeralImage} ; then echo "failed to verify with keyless" fi echo '::endgroup::' echo '::group:: Create test namespace and label for verification' export NS=demo-ephemeral-verification kubectl create namespace ${NS} kubectl label namespace ${NS} policy.sigstore.dev/include=true echo '::endgroup::' echo '::group:: test pod success' # We signed this above, this should work if ! kubectl run -n ${NS} poddemo --image=${demoEphemeralImage} ; then echo Failed to create Pod in namespace with matching signature! exit 1 else echo Succcessfully created Pod with signed image fi echo '::endgroup::' echo '::group:: Set no-match policy to deny' kubectl patch configmap/config-policy-controller \ --namespace cosign-system \ --type merge \ --patch '{"data":{"no-match-policy":"deny"}}' # allow for propagation sleep 10 echo '::endgroup::' ephemeralContainerImage="busybox@sha256:9810966b5f712084ea05bf28fc8ba2c8fb110baa2531a10e2da52c1efc504698" echo '::group:: test rejection of ephemeral container that does not have any signature' # We want to validate that ephemeral containers are validated, and rejected for this example if kubectl debug poddemo -n ${NS} --image=${ephemeralContainerImage} ; then echo Failed to block EphemeralContainer for Pod in namespace with no matching signature! exit 1 else echo Succcessfully created EphemeralContainer for Pod without any valid signed image fi echo '::endgroup::' kubernetesVersion=$(kubectl version -o json | jq -rj '.serverVersion|.major,".",.minor') echo '::group:: Create Ephemeral Container with valid signature for the image' if ! kubectl debug poddemo -n ${NS} --image=${demoEphemeralImage}; then # Check if the kubernetes version is v1.22 then ignore the error as ephemeral containers are not supported if [ "$(echo -e "1.22\n${kubernetesVersion}" | sort -V | head -1)" == "1.22" ]; then echo "Ignore error: Ephemeral containers are not supported in Kubernetes v1.22" else echo Failed to create Ephemeral Container with a valid signature ${kubernetesVersion} exit 1 fi else echo Succcessfully created Ephemeral Container with a valid signature fi echo '::endgroup::' echo '::group::' Cleanup kubectl delete cip --all kubectl delete ns ${NS} echo '::endgroup::' ================================================ FILE: test/e2e_test_cluster_image_policy_from_configmap_with_fetch_config_file.sh ================================================ #!/usr/bin/env bash # # 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. #set -ex set -e # This is a timestamp server that has multiarch that we just use for testing # evaluating CIP level policy validations. export demoimage="ghcr.io/sigstore/timestamp-server@sha256:dcf2f3a640bfb0a5d17aabafb34b407fe4403363c715718ab305a62b3606540d" # To simplify testing failures, use this function to execute a kubectl to create # our job and verify that the failure is expected. assert_error() { local KUBECTL_OUT_FILE="/tmp/kubectl.failure.out" match="$@" echo looking for ${match} kubectl delete job job-that-fails -n ${NS} --ignore-not-found=true if kubectl create -n ${NS} job job-that-fails --image=${demoimage} 2> ${KUBECTL_OUT_FILE} ; then echo Failed to block expected Job failure! exit 1 else echo Successfully blocked Job creation with expected error: "${match}" if ! grep -q "${match}" ${KUBECTL_OUT_FILE} ; then echo Did not get expected failure message, wanted "${match}", got cat ${KUBECTL_OUT_FILE} exit 1 fi fi } echo '::group:: Create test namespace and label for verification' kubectl create namespace demo-config-file-with-configmap kubectl label namespace demo-config-file-with-configmap policy.sigstore.dev/include=true export NS=demo-config-file-with-configmap echo '::endgroup::' # Create the configmap that contains our cue policy. Note that as is, it will # fail. kubectl create -n cosign-system configmap policy-config --from-file=policy=./test/testdata/policies/cue-policy-config.cue # Note that we put this in a for loop to make sure the webhook is actually # up and running before proceeding with the tests. echo '::group:: Deploy ClusterImagePolicy with config file that should fail' for i in {1..10} do if kubectl apply -f ./test/testdata/policy-controller/e2e/cip-config-file-policy-from-configmap.yaml ; then echo successfully applied CIP break fi if [ "$i" == 10 ]; then echo failed to apply CIP exit 1 fi echo failed to apply CIP. Attempt numer "$i", retrying sleep 2 done # allow things to propagate sleep 5 echo '::endgroup::' echo '::group:: validate failure' expected_error='failed evaluating cue policy for ClusterImagePolicy: failed to evaluate the policy with error: config."linux/amd64".config.User: conflicting values' assert_error ${expected_error} echo '::endgroup::' # Note that we update the configmap here, which should propagate through to the # serialized CIP, so testing that as well here. echo '::group:: Update configmap with passing values' kubectl -n cosign-system get cm -oyaml policy-config | sed 's/65530/65532/' | kubectl apply -f - # allow things to propagate sleep 5 echo '::endgroup::' echo '::group:: test job success' # This one should pass since the User is what we specified in the CIP policy. if ! kubectl create -n ${NS} job demo --image=${demoimage} ; then echo Failed to create Job in namespace with valid CIP policy! exit 1 else echo Succcessfully created Job with signed image fi echo '::endgroup::' echo '::group::' Cleanup kubectl delete cip --all kubectl delete ns ${NS} echo '::endgroup::' ================================================ FILE: test/e2e_test_cluster_image_policy_from_url.sh ================================================ #!/usr/bin/env bash # # 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. #set -ex set -e # This is a timestamp server that has multiarch that we just use for testing # evaluating CIP level policy validations. export demoimage="ghcr.io/sigstore/timestamp-server@sha256:dcf2f3a640bfb0a5d17aabafb34b407fe4403363c715718ab305a62b3606540d" # To simplify testing failures, use this function to execute a kubectl to create # our job and verify that the failure is expected. assert_error() { local KUBECTL_OUT_FILE="/tmp/kubectl.failure.out" match="$@" echo looking for ${match} kubectl delete job job-that-fails -n ${NS} --ignore-not-found=true if kubectl create -n ${NS} job job-that-fails --image=${demoimage} 2> ${KUBECTL_OUT_FILE} ; then echo Failed to block expected Job failure! exit 1 else echo Successfully blocked Job creation with expected error: "${match}" if ! grep -q "${match}" ${KUBECTL_OUT_FILE} ; then echo Did not get expected failure message, wanted "${match}", got cat ${KUBECTL_OUT_FILE} exit 1 fi fi } echo '::group:: Create test namespace and label for verification' kubectl create namespace demo-policy-with-url kubectl label namespace demo-policy-with-url policy.sigstore.dev/include=true export NS=demo-policy-with-url echo '::endgroup::' # Note that we put this in a for loop to make sure the webhook is actually # up and running before proceeding with the tests. echo '::group:: Deploy ClusterImagePolicy with config file that should fail due to cue errors' for i in {1..10} do if kubectl apply -f ./test/testdata/policy-controller/e2e/cip-policy-from-url.yaml ; then echo successfully applied CIP break fi if [ "$i" == 10 ]; then echo failed to apply CIP exit 1 fi echo failed to apply CIP. Attempt numer "$i", retrying sleep 2 done # allow things to propagate sleep 5 echo '::endgroup::' echo '::group:: validate failure' expected_error='failed evaluating cue policy for ClusterImagePolicy: failed to evaluate the policy with error: config."linux/amd64".config.User: conflicting values' assert_error ${expected_error} echo '::endgroup::' echo '::group:: Update policy url and sha256sum with passing cue values' kubectl patch cip image-policy-url --type "json" \ -p '[{"op":"replace", "path":"/spec/policy/remote/url", "value":"https://gist.githubusercontent.com/hectorj2f/af0d32d4be4bf2710cff76c397a14751/raw/d4dd87fffdf9624a21e62b8719e3ce8d61334ab9/policy-controller-test-success-cue"},{"op":"replace", "path":"/spec/policy/remote/sha256sum", "value":"45eb2cce1c84418d615f3e56c701451b63d58b95f9559dfa1d5254cb851358d3"}]' # allow for propagation sleep 5 echo '::endgroup::' echo '::group:: test job success' # This one should pass since the User is what we specified in the CIP policy. if ! kubectl create -n ${NS} job demo --image=${demoimage} ; then echo Failed to create Job in namespace with valid CIP policy! exit 1 else echo Succcessfully created Job with signed image fi echo '::endgroup::' echo '::group::' Cleanup kubectl delete cip --all kubectl delete ns ${NS} echo '::endgroup::' ================================================ FILE: test/e2e_test_cluster_image_policy_no_tuf.sh ================================================ #!/usr/bin/env bash # # 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. set -ex if [[ -z "${KO_DOCKER_REPO}" ]]; then echo "Must specify env variable KO_DOCKER_REPO" exit 1 fi if [[ -z "${FULCIO_URL}" ]]; then echo "Must specify env variable FULCIO_URL" exit 1 fi if [[ -z "${REKOR_URL}" ]]; then echo "Must specify env variable REKOR_URL" exit 1 fi if [[ "${NON_REPRODUCIBLE}"=="1" ]]; then echo "creating non-reproducible build by adding a timestamp" export TIMESTAMP=`date +%s` else export TIMESTAMP="TIMESTAMP" fi # To simplify testing failures, use this function to execute a kubectl to create # our job and verify that the failure is expected. assert_error() { local KUBECTL_OUT_FILE="/tmp/kubectl.failure.out" match="$@" echo looking for ${match} kubectl delete job demo -n ${NS} --ignore-not-found=true if kubectl create -n ${NS} job demo --image=${demoimage} 2> ${KUBECTL_OUT_FILE} ; then echo Failed to block expected Job failure! exit 1 else echo Successfully blocked Job creation with expected error: "${match}" if ! grep -q "${match}" ${KUBECTL_OUT_FILE} ; then echo Did not get expected failure message, wanted "${match}", got cat ${KUBECTL_OUT_FILE} exit 1 fi fi } # Publish test image echo '::group:: publish test image demoimage' pushd $(mktemp -d) go mod init example.com/demo cat < main.go package main import "fmt" func main() { fmt.Println("hello world TIMESTAMP") } EOF sed -i'' -e "s@TIMESTAMP@${TIMESTAMP}@g" main.go cat main.go export demoimage=`ko publish -B example.com/demo` echo Created image $demoimage popd echo '::endgroup::' echo '::group:: Create and label new namespace for verification' kubectl create namespace demo-no-tuf kubectl label namespace demo-no-tuf policy.sigstore.dev/include=true export NS=demo-no-tuf echo '::endgroup::' echo '::group:: Generate New Signing Key that we use for key-ful signing' COSIGN_PASSWORD="" cosign generate-key-pair echo '::endgroup::' # Create CIP that requires a signature with a key. echo '::group:: Create CIP that requires a keyful signature' yq '. | .spec.authorities[0].key.data |= load_str("cosign.pub")' ./test/testdata/policy-controller/e2e/cip-key-no-rekor.yaml | kubectl apply -f - # Give the policy controller a moment to update the configmap # and pick up the change in the admission controller. sleep 5 echo '::endgroup::' # This image has not been signed with our key # so should fail echo '::group:: test job rejection' expected_error='no signatures found' assert_error ${expected_error} echo '::endgroup::' # Sign it with key echo '::group:: Sign demoimage with key, do not add to rekor' COSIGN_PASSWORD="" cosign sign --tlog-upload=false --key cosign.key --allow-insecure-registry ${demoimage} echo '::endgroup::' # TODO(vaikas): This fails because it doesn't have a Rekor entry. Which it obvs # does not because of --tlog-upload=false above. #echo '::group:: Verify demoimage with cosign key' #cosign verify --key cosign.pub --allow-insecure-registry ${demoimage} #echo '::endgroup::' # Then let's test attestations work too with key. echo '::group:: Create CIP that requires a keyful attestation' yq '. | .spec.authorities[0].key.data |= load_str("cosign.pub")' ./test/testdata/policy-controller/e2e/cip-key-with-attestations-no-rekor.yaml | kubectl apply -f - # Give the policy controller a moment to update the configmap # and pick up the change in the admission controller. sleep 5 echo '::endgroup::' # This image has been signed with key, but does not have a key attestation # so should fail echo '::group:: test job rejection' expected_error='no matching attestations' assert_error ${expected_error} echo '::endgroup::' # Fine, so create an attestation for it. echo '::group:: create keyful attestation, do not add to rekor' echo -n 'foobar key e2e test' > ./predicate-file-key-custom COSIGN_PASSWORD="" cosign attest --predicate ./predicate-file-key-custom --key ./cosign.key --allow-insecure-registry --tlog-upload=false ${demoimage} # TODO(vaikas): This again fails though it really shouldn't. #cosign verify-attestation --key ./cosign.pub --allow-insecure-registry ${demoimage} echo '::endgroup::' export KUBECTL_SUCCESS_FILE="/tmp/kubectl.success.out" echo '::group:: test job success with key signature and key attestation' # We signed this with key and it has a key attestation, so should pass. if ! kubectl create -n ${NS} job demo2 --image=${demoimage} 2> ${KUBECTL_SUCCESS_FILE} ; then echo Failed to create job with both key signature and attestation cat ${KUBECTL_SUCCESS_FILE} exit 1 else echo Created the job with key signature and an attestation fi echo '::endgroup::' echo '::group::' Cleanup kubectl delete cip --all kubectl delete ns ${NS} rm cosign.key cosign.pub echo '::endgroup::' ================================================ FILE: test/e2e_test_cluster_image_policy_with_attestations.sh ================================================ #!/usr/bin/env bash # # 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. set -ex if [[ -z "${OIDC_TOKEN}" ]]; then if [[ -z "${ISSUER_URL}" ]]; then echo "Must specify either env variable OIDC_TOKEN or ISSUER_URL" exit 1 else export OIDC_TOKEN=`curl -s ${ISSUER_URL}` fi fi if [[ -z "${KO_DOCKER_REPO}" ]]; then echo "Must specify env variable KO_DOCKER_REPO" exit 1 fi if [[ -z "${FULCIO_URL}" ]]; then echo "Must specify env variable FULCIO_URL" exit 1 fi if [[ -z "${REKOR_URL}" ]]; then echo "Must specify env variable REKOR_URL" exit 1 fi if [[ -z "${TUF_ROOT_FILE}" ]]; then echo "must specify env variable TUF_ROOT_FILE" exit 1 fi if [[ -z "${TUF_MIRROR}" ]]; then echo "must specify env variable TUF_MIRROR" exit 1 fi if [[ "${NON_REPRODUCIBLE}"=="1" ]]; then echo "creating non-reproducible build by adding a timestamp" export TIMESTAMP=`date +%s` else export TIMESTAMP="TIMESTAMP" fi # Initialize cosign with our TUF root cosign initialize --mirror ${TUF_MIRROR} --root ${TUF_ROOT_FILE} # To simplify testing failures, use this function to execute a kubectl to create # our job and verify that the failure is expected. assert_error() { local KUBECTL_OUT_FILE="/tmp/kubectl.failure.out" match="$@" echo looking for ${match} kubectl delete job demo -n ${NS} --ignore-not-found=true if kubectl create -n ${NS} job demo --image=${demoimage} 2> ${KUBECTL_OUT_FILE} ; then echo Failed to block expected Job failure! exit 1 else echo Successfully blocked Job creation with expected error: "${match}" if ! grep -q "${match}" ${KUBECTL_OUT_FILE} ; then echo Did not get expected failure message, wanted "${match}", got cat ${KUBECTL_OUT_FILE} exit 1 fi fi } # Publish test image echo '::group:: publish test image demoimage' pushd $(mktemp -d) go mod init example.com/demo cat < main.go package main import "fmt" func main() { fmt.Println("hello world TIMESTAMP") } EOF sed -i'' -e "s@TIMESTAMP@${TIMESTAMP}@g" main.go cat main.go export demoimage=`ko publish -B example.com/demo` echo Created image $demoimage popd echo '::endgroup::' echo '::group:: Create and label new namespace for verification' kubectl create namespace demo-attestations kubectl label namespace demo-attestations policy.sigstore.dev/include=true export NS=demo-attestations echo '::endgroup::' echo '::group:: Create CIP that requires keyless signature' kubectl apply -f ./test/testdata/policy-controller/e2e/cip-keyless.yaml # allow things to propagate sleep 5 echo '::endgroup::' # This image has not been signed at all, so should get auto-reject echo '::group:: test job rejection' expected_error='no signatures found' assert_error ${expected_error} echo '::endgroup::' echo '::group:: Sign demoimage with keyless' cosign sign --rekor-url ${REKOR_URL} --fulcio-url ${FULCIO_URL} --yes --allow-insecure-registry ${demoimage} --identity-token ${OIDC_TOKEN} echo '::endgroup::' echo '::group:: Create CIP that requires keyless custom attestation with policy' kubectl apply -f ./test/testdata/policy-controller/e2e/cip-keyless-with-attestations.yaml # allow things to propagate sleep 5 echo '::endgroup::' # This image has been signed, but does not have an attestation, so should fail. echo '::group:: test job rejection' expected_error='no matching attestations' assert_error ${expected_error} echo '::endgroup::' # Ok, cool. So attest and it should pass. echo '::group:: Create one keyless attestation and verify it' echo -n 'foobar e2e test' > ./predicate-file-custom cosign attest --predicate ./predicate-file-custom --fulcio-url ${FULCIO_URL} --rekor-url ${REKOR_URL} --allow-insecure-registry --yes ${demoimage} --identity-token ${OIDC_TOKEN} cosign verify-attestation --type=custom --rekor-url ${REKOR_URL} --allow-insecure-registry --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage} echo '::endgroup::' echo '::group:: test job success' # We signed this with keyless and it has a keyless attestation, so should # pass. export KUBECTL_SUCCESS_FILE="/tmp/kubectl.success.out" if ! kubectl create -n ${NS} job demo --image=${demoimage} 2> ${KUBECTL_SUCCESS_FILE} ; then echo Failed to create job with keyless signature and an attestation cat ${KUBECTL_SUCCESS_FILE} exit 1 else echo Created the job with keyless signature and an attestation fi kubectl delete -n ${NS} job demo echo '::endgroup::' echo '::group:: Generate New Signing Key that we use for key-ful signing' COSIGN_PASSWORD="" cosign generate-key-pair echo '::endgroup::' # Ok, so now we have satisfied the keyless requirements, one signature, one # custom attestation. Let's now do it for 'keyful' one. echo '::group:: Create CIP that requires a keyful signature' yq '. | .spec.authorities[0].key.data |= load_str("cosign.pub")' ./test/testdata/policy-controller/e2e/cip-key.yaml | kubectl apply -f - # Give the policy controller a moment to update the configmap # and pick up the change in the admission controller. sleep 5 echo '::endgroup::' # This image has been signed with keyless, but does not have a keyful signature # so should fail echo '::group:: test job rejection' expected_error='no matching signatures' assert_error ${expected_error} echo '::endgroup::' # Sign it with key echo '::group:: Sign demoimage with key, and add to rekor' COSIGN_PASSWORD="" cosign sign --key cosign.key --yes --allow-insecure-registry --rekor-url ${REKOR_URL} ${demoimage} echo '::endgroup::' echo '::group:: Verify demoimage with cosign key' cosign verify --key cosign.pub --rekor-url ${REKOR_URL} --allow-insecure-registry --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage} echo '::endgroup::' # Ok, so now we have satisfied the keyless requirements, one signature, one # custom attestation, and one 'keyful' one. But it will now be missing a # keyful attestation, so let's add that requirement. echo '::group:: Create CIP that requires a keyful attestation' yq '. | .spec.authorities[0].key.data |= load_str("cosign.pub")' ./test/testdata/policy-controller/e2e/cip-key-with-attestations.yaml | kubectl apply -f - # Give the policy controller a moment to update the configmap # and pick up the change in the admission controller. sleep 5 echo '::endgroup::' # This image has been signed with key, but does not have a key attestation # so should fail echo '::group:: test job rejection' expected_error='no matching attestations' assert_error ${expected_error} echo '::endgroup::' # Fine, so create an attestation for it that's different from the keyless one echo '::group:: create keyful attestation, add add to rekor' echo -n 'foobar key e2e test' > ./predicate-file-key-custom COSIGN_PASSWORD="" cosign attest --predicate ./predicate-file-key-custom --rekor-url ${REKOR_URL} --key ./cosign.key --allow-insecure-registry --yes ${demoimage} cosign verify-attestation --key ./cosign.pub --allow-insecure-registry --rekor-url ${REKOR_URL} --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage} echo '::endgroup::' echo '::group:: test job success with key / keyless' # We signed this with keyless and key and it has a key/keyless attestation, so # should pass. if ! kubectl create -n ${NS} job demo2 --image=${demoimage} 2> ${KUBECTL_SUCCESS_FILE} ; then echo Failed to create job with both key/keyless signatures and attestations cat ${KUBECTL_SUCCESS_FILE} exit 1 else echo Created the job with keyless/key signature and an attestations fi echo '::endgroup::' # We have to fix this bug, so bail for now so we get passing tests. # https://github.com/sigstore/policy-controller/issues/130 echo "***********Exiting early due to bug 130*********" exit 0 # So at this point, we have two CIP, one that requires keyless/key sig # and attestations with both. Let's take it up a notch. # Let's create a policy that requires both a keyless and keyful # signature on the image, as well as two attestations signed by the keyless and # one custom attestation that's signed by key. # Note we have to bake in the inline data from the keys above echo '::group:: Add cip for two signatures and two attestations' yq '. | .spec.authorities[1].key.data |= load_str("cosign.pub") | .spec.authorities[3].key.data |= load_str("cosign.pub")' ./test/testdata/policy-controller/e2e/cip-requires-two-signatures-and-two-attestations.yaml | kubectl apply -f - # Give the policy controller a moment to update the configmap # and pick up the change in the admission controller. sleep 5 echo '::endgroup::' # The CIP policy is the one that should fail now because it doesn't have enough # attestations echo '::group:: test job rejection' expected_error='failed to evaluate the policy with error: authorityMatches.keylessattMinAttestations' assert_error ${expected_error} echo '::endgroup::' echo '::group:: Create vuln keyless attestation and verify it' cosign attest --predicate ./test/testdata/attestations/vuln-predicate.json --type=vuln --fulcio-url ${FULCIO_URL} --rekor-url ${REKOR_URL} --allow-insecure-registry --yes ${demoimage} --identity-token ${OIDC_TOKEN} cosign verify-attestation --type=vuln --rekor-url ${REKOR_URL} --allow-insecure-registry --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage} echo '::endgroup::' echo '::group:: test job success' # We signed this with key and keyless and it has two keyless attestations and # it has one key attestation, so it should succeed. if ! kubectl create -n ${NS} job demo3 --image=${demoimage} 2> ${KUBECTL_SUCCESS_FILE} ; then echo Failed to create job that has two signatures and 3 attestations cat ${KUBECTL_SUCCESS_FILE} exit 1 fi echo '::endgroup::' echo '::group::' Cleanup kubectl delete cip --all kubectl delete ns ${NS} rm cosign.key cosign.pub echo '::endgroup::' ================================================ FILE: test/e2e_test_cluster_image_policy_with_attestations_rego.sh ================================================ #!/usr/bin/env bash # # 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. set -ex if [[ -z "${OIDC_TOKEN}" ]]; then if [[ -z "${ISSUER_URL}" ]]; then echo "Must specify either env variable OIDC_TOKEN or ISSUER_URL" exit 1 else export OIDC_TOKEN=`curl -s ${ISSUER_URL}` fi fi if [[ -z "${KO_DOCKER_REPO}" ]]; then echo "Must specify env variable KO_DOCKER_REPO" exit 1 fi if [[ -z "${FULCIO_URL}" ]]; then echo "Must specify env variable FULCIO_URL" exit 1 fi if [[ -z "${REKOR_URL}" ]]; then echo "Must specify env variable REKOR_URL" exit 1 fi if [[ -z "${TUF_ROOT_FILE}" ]]; then echo "must specify env variable TUF_ROOT_FILE" exit 1 fi if [[ -z "${TUF_MIRROR}" ]]; then echo "must specify env variable TUF_MIRROR" exit 1 fi if [[ "${NON_REPRODUCIBLE}"=="1" ]]; then echo "creating non-reproducible build by adding a timestamp" export TIMESTAMP=`date +%s` else export TIMESTAMP="TIMESTAMP" fi # Initialize cosign with our TUF root cosign initialize --mirror ${TUF_MIRROR} --root ${TUF_ROOT_FILE} # To simplify testing failures, use this function to execute a kubectl to create # our job and verify that the failure is expected. assert_error() { local KUBECTL_OUT_FILE="/tmp/kubectl.failure.out" match="$@" echo looking for ${match} kubectl delete job demo -n ${NS} --ignore-not-found=true if kubectl create -n ${NS} job demo --image=${demoimage} 2> ${KUBECTL_OUT_FILE} ; then echo Failed to block expected Job failure! exit 1 else echo Successfully blocked Job creation with expected error: "${match}" if ! grep -q "${match}" ${KUBECTL_OUT_FILE} ; then echo Did not get expected failure message, wanted "${match}", got cat ${KUBECTL_OUT_FILE} exit 1 fi fi } # Publish test image echo '::group:: publish test image demoimage' pushd $(mktemp -d) go mod init example.com/demo cat < main.go package main import "fmt" func main() { fmt.Println("hello world TIMESTAMP") } EOF sed -i'' -e "s@TIMESTAMP@${TIMESTAMP}@g" main.go cat main.go export demoimage=`ko publish -B example.com/demo` echo Created image $demoimage popd echo '::endgroup::' echo '::group:: Create and label new namespace for verification' kubectl create namespace demo-attestations-rego kubectl label namespace demo-attestations-rego policy.sigstore.dev/include=true export NS=demo-attestations-rego echo '::endgroup::' echo '::group:: Create CIP that requires keyless signature' kubectl apply -f ./test/testdata/policy-controller/e2e/cip-keyless.yaml # allow things to propagate sleep 5 echo '::endgroup::' # This image has not been signed at all, so should get auto-reject echo '::group:: test job rejection' expected_error='no signatures found' assert_error ${expected_error} echo '::endgroup::' echo '::group:: Sign demoimage with keyless' cosign sign --rekor-url ${REKOR_URL} --fulcio-url ${FULCIO_URL} --yes --allow-insecure-registry ${demoimage} --identity-token ${OIDC_TOKEN} echo '::endgroup::' echo '::group:: Create CIP that requires keyless custom attestation with policy that requires data == "foobar e2e test"' kubectl apply -f ./test/testdata/policy-controller/e2e/cip-keyless-with-attestations-rego.yaml # allow things to propagate sleep 5 echo '::endgroup::' # This image has been signed, but does not have an attestation, so should fail. echo '::group:: test job rejection' expected_error='no matching attestations' assert_error ${expected_error} echo '::endgroup::' # Ok, cool. So attest and it should still fail because the data does not match. echo '::group:: Create one keyless attestation with incorrect data and verify it' echo -n 'barfoo e2e test' > ./predicate-file-custom-fails cosign attest --predicate ./predicate-file-custom-fails --fulcio-url ${FULCIO_URL} --rekor-url ${REKOR_URL} --allow-insecure-registry --yes ${demoimage} --identity-token ${OIDC_TOKEN} cosign verify-attestation --type=custom --rekor-url ${REKOR_URL} --allow-insecure-registry --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage} echo '::endgroup::' # This image has been signed, and has attestation, but data is not right echo '::group:: test job rejection because the data does not match wanted policy' expected_error='failed evaluating rego policy for type custom-match-predicate: policy is not compliant for query' assert_error ${expected_error} echo '::endgroup::' # Create another attestation with the data to match what our policy wants. echo '::group:: Create another keyless attestation with correct data and verify it' echo -n 'foobar e2e test' > ./predicate-file-custom-works cosign attest --predicate ./predicate-file-custom-works --fulcio-url ${FULCIO_URL} --rekor-url ${REKOR_URL} --allow-insecure-registry --yes ${demoimage} --identity-token ${OIDC_TOKEN} cosign verify-attestation --type=custom --rekor-url ${REKOR_URL} --allow-insecure-registry --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage} echo '::endgroup::' echo '::group:: test job success' # We signed this with keyless and it has a keyless attestation, so should # pass. export KUBECTL_SUCCESS_FILE="/tmp/kubectl.success.out" if ! kubectl create -n ${NS} job demo --image=${demoimage} 2> ${KUBECTL_SUCCESS_FILE} ; then echo Failed to create job with keyless signature and an attestation cat ${KUBECTL_SUCCESS_FILE} exit 1 else echo Created the job with keyless signature and an attestation fi kubectl delete -n ${NS} job demo echo '::endgroup::' echo '::group:: Generate New Signing Key that we use for key-ful signing' COSIGN_PASSWORD="" cosign generate-key-pair echo '::endgroup::' # Ok, so now we have satisfied the keyless requirements, one signature, one # custom attestation. Let's now do it for 'keyful' one. echo '::group:: Create CIP that requires a keyful signature' yq '. | .spec.authorities[0].key.data |= load_str("cosign.pub")' ./test/testdata/policy-controller/e2e/cip-key.yaml | kubectl apply -f - # Give the policy controller a moment to update the configmap # and pick up the change in the admission controller. sleep 5 echo '::endgroup::' # This image has been signed with keyless, but does not have a keyful signature # so should fail echo '::group:: test job rejection' expected_error='no matching signatures' assert_error ${expected_error} echo '::endgroup::' # Sign it with key echo '::group:: Sign demoimage with key, and add to rekor' COSIGN_PASSWORD="" cosign sign --key cosign.key --yes --allow-insecure-registry --rekor-url ${REKOR_URL} ${demoimage} echo '::endgroup::' echo '::group:: Verify demoimage with cosign key' cosign verify --key cosign.pub --rekor-url ${REKOR_URL} --allow-insecure-registry --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage} echo '::endgroup::' # Ok, so now we have satisfied the keyless requirements, one signature, one # custom attestation, and one 'keyful' one. But it will now be missing a # keyful attestation, so let's add that requirement. echo '::group:: Create CIP that requires a keyful attestation' yq '. | .spec.authorities[0].key.data |= load_str("cosign.pub")' ./test/testdata/policy-controller/e2e/cip-key-with-attestations-rego.yaml | kubectl apply -f - # Give the policy controller a moment to update the configmap # and pick up the change in the admission controller. sleep 5 echo '::endgroup::' # This image has been signed with key, but does not have a key attestation # so should fail echo '::group:: test job rejection' expected_error='no matching attestations' assert_error ${expected_error} echo '::endgroup::' # Fine, so create an attestation for it that's different from the keyless one echo '::group:: create keyful attestation, add add to rekor' echo -n 'foobar key e2e test' > ./predicate-file-key-custom COSIGN_PASSWORD="" cosign attest --predicate ./predicate-file-key-custom --rekor-url ${REKOR_URL} --key ./cosign.key --allow-insecure-registry --yes ${demoimage} cosign verify-attestation --key ./cosign.pub --allow-insecure-registry --rekor-url ${REKOR_URL} --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage} echo '::endgroup::' echo '::group:: test job success with key / keyless' # We signed this with keyless and key and it has a key/keyless attestation, so # should pass. if ! kubectl create -n ${NS} job demo2 --image=${demoimage} 2> ${KUBECTL_SUCCESS_FILE} ; then echo Failed to create job with both key/keyless signatures and attestations cat ${KUBECTL_SUCCESS_FILE} exit 1 else echo Created the job with keyless/key signature and an attestations fi echo '::endgroup::' echo '::group::' Cleanup kubectl delete cip --all kubectl delete ns ${NS} rm cosign.key cosign.pub echo '::endgroup::' ================================================ FILE: test/e2e_test_cluster_image_policy_with_fetch_config_file.sh ================================================ #!/usr/bin/env bash # # 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. #set -ex set -e # This is a timestamp server that has multiarch that we just use for testing # evaluating CIP level policy validations. export demoimage="ghcr.io/sigstore/timestamp-server@sha256:dcf2f3a640bfb0a5d17aabafb34b407fe4403363c715718ab305a62b3606540d" # To simplify testing failures, use this function to execute a kubectl to create # our job and verify that the failure is expected. assert_error() { local KUBECTL_OUT_FILE="/tmp/kubectl.failure.out" match="$@" echo looking for ${match} kubectl delete job job-that-fails -n ${NS} --ignore-not-found=true if kubectl create -n ${NS} job job-that-fails --image=${demoimage} 2> ${KUBECTL_OUT_FILE} ; then echo Failed to block expected Job failure! exit 1 else echo Successfully blocked Job creation with expected error: "${match}" if ! grep -q "${match}" ${KUBECTL_OUT_FILE} ; then echo Did not get expected failure message, wanted "${match}", got cat ${KUBECTL_OUT_FILE} exit 1 fi fi } echo '::group:: Create test namespace and label for verification' kubectl create namespace demo-config-file kubectl label namespace demo-config-file policy.sigstore.dev/include=true export NS=demo-config-file echo '::endgroup::' # Note that we put this in a for loop to make sure the webhook is actually # up and running before proceeding with the tests. echo '::group:: Deploy ClusterImagePolicy with config file that should fail' for i in {1..10} do if kubectl apply -f ./test/testdata/policy-controller/e2e/cip-config-file-policy-fails.yaml ; then echo successfully applied failing CIP break fi if [ "$i" == 10 ]; then echo failed to apply failing CIP exit 1 fi echo failed to apply failing CIP. Attempt numer "$i", retrying sleep 2 done # allow things to propagate sleep 5 echo '::endgroup::' echo '::group:: validate failure ' expected_error='failed evaluating cue policy for ClusterImagePolicy: failed to evaluate the policy with error: config."linux/amd64".config.User: conflicting values' assert_error ${expected_error} echo '::endgroup::' echo '::group:: Remove failingClusterImagePolicy and create one that passes' kubectl delete -f ./test/testdata/policy-controller/e2e/cip-config-file-policy-fails.yaml kubectl apply -f ./test/testdata/policy-controller/e2e/cip-config-file-policy.yaml # allow things to propagate sleep 5 echo '::endgroup::' echo '::group:: test job success' # This one should pass since the User is what we specified in the CIP policy. if ! kubectl create -n ${NS} job demo --image=${demoimage} ; then echo Failed to create Job in namespace with valid CIP policy! exit 1 else echo Succcessfully created Job with signed image fi echo '::endgroup::' echo '::group::' Cleanup kubectl delete cip --all kubectl delete ns ${NS} echo '::endgroup::' ================================================ FILE: test/e2e_test_cluster_image_policy_with_include_objectmeta.sh ================================================ #!/usr/bin/env bash # # 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. #set -ex set -e # This is a timestamp server that we just use for testing evaluating CIP level # policy validations. export demoimage="ghcr.io/sigstore/timestamp-server@sha256:dcf2f3a640bfb0a5d17aabafb34b407fe4403363c715718ab305a62b3606540d" # To simplify testing failures, use this function to execute a kubectl to create # our pod and verify that the failure is expected. Note that this sets a label # that we expect to fail assert_error() { local KUBECTL_OUT_FILE="/tmp/kubectl.failure.out" match="$@" echo looking for ${match} kubectl delete pod pod-that-fails -n ${NS} --ignore-not-found=true if kubectl run -n ${NS} -l="foo=bar" pod-that-fails --image=${demoimage} 2> ${KUBECTL_OUT_FILE} ; then echo Failed to block expected Pod failure! exit 1 else echo Successfully blocked Pod creation with expected error: "${match}" if ! grep -q "${match}" ${KUBECTL_OUT_FILE} ; then echo Did not get expected failure message, wanted "${match}", got cat ${KUBECTL_OUT_FILE} exit 1 fi fi } echo '::group:: Create test namespace and label for verification' kubectl create namespace demo-include-objectmeta kubectl label namespace demo-include-objectmeta policy.sigstore.dev/include=true export NS=demo-include-objectmeta echo '::endgroup::' # Note that we put this in a for loop to make sure the webhook is actually # up and running before proceeding with the tests. echo '::group:: Deploy ClusterImagePolicy with label that should fail' for i in {1..10} do if kubectl apply -f ./test/testdata/policy-controller/e2e/cip-include-objectmeta-fails.yaml ; then echo successfully applied failing CIP break fi if [ "$i" == 10 ]; then echo failed to apply failing CIP exit 1 fi echo failed to apply failing CIP. Attempt numer "$i", retrying sleep 2 done # allow things to propagate sleep 5 echo '::endgroup::' echo '::group:: validate failure ' expected_error='failed evaluating cue policy for ClusterImagePolicy: failed to evaluate the policy with error: metadata.labels.foo: conflicting values "bar" and "non-bar"' assert_error ${expected_error} echo '::endgroup::' echo '::group:: Remove failing ClusterImagePolicy and create one that passes' kubectl delete -f ./test/testdata/policy-controller/e2e/cip-include-objectmeta-fails.yaml kubectl apply -f ./test/testdata/policy-controller/e2e/cip-include-objectmeta.yaml # allow things to propagate sleep 5 echo '::endgroup::' echo '::group:: test job success' # This one should pass since the label is what we specified in the CIP # policy. if ! kubectl run -n ${NS} -l="foo=bar" demo --image=${demoimage} ; then echo Failed to create Pod in namespace with valid CIP policy! exit 1 else echo Succcessfully created Pod with correct labels fi echo '::endgroup::' echo '::group::' Cleanup kubectl delete cip --all kubectl delete ns ${NS} echo '::endgroup::' ================================================ FILE: test/e2e_test_cluster_image_policy_with_include_spec.sh ================================================ #!/usr/bin/env bash # # 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. #set -ex set -e # This is a timestamp server that has multiarch that we just use for testing # evaluating CIP level policy validations. export demoimage="ghcr.io/sigstore/timestamp-server@sha256:dcf2f3a640bfb0a5d17aabafb34b407fe4403363c715718ab305a62b3606540d" # To simplify testing failures, use this function to execute a kubectl to create # our pod and verify that the failure is expected. # Note that we run this as a pod since our spec checks for pod specs only. assert_error() { local KUBECTL_OUT_FILE="/tmp/kubectl.failure.out" match="$@" echo looking for ${match} kubectl delete pod pod-that-fails -n ${NS} --ignore-not-found=true if kubectl run -n ${NS} pod-that-fails --image=${demoimage} 2> ${KUBECTL_OUT_FILE} ; then echo Failed to block expected Pod failure! exit 1 else echo Successfully blocked Pod creation with expected error: "${match}" if ! grep -q "${match}" ${KUBECTL_OUT_FILE} ; then echo Did not get expected failure message, wanted "${match}", got cat ${KUBECTL_OUT_FILE} exit 1 fi fi } echo '::group:: Create test namespace and label for verification' kubectl create namespace demo-include-spec kubectl label namespace demo-include-spec policy.sigstore.dev/include=true export NS=demo-include-spec echo '::endgroup::' # Note that we put this in a for loop to make sure the webhook is actually # up and running before proceeding with the tests. echo '::group:: Deploy ClusterImagePolicy with included spec that should fail' for i in {1..10} do if kubectl apply -f ./test/testdata/policy-controller/e2e/cip-include-spec-fails.yaml ; then echo successfully applied failing CIP break fi if [ "$i" == 10 ]; then echo failed to apply failing CIP exit 1 fi echo failed to apply failing CIP. Attempt numer "$i", retrying sleep 2 done # allow things to propagate sleep 5 echo '::endgroup::' echo '::group:: validate failure ' expected_error='failed evaluating cue policy for ClusterImagePolicy: failed to evaluate the policy with error: spec.serviceAccount: conflicting values "default" and "non-default"' assert_error ${expected_error} echo '::endgroup::' echo '::group:: Remove failingClusterImagePolicy and create one that passes' kubectl delete -f ./test/testdata/policy-controller/e2e/cip-include-spec-fails.yaml kubectl apply -f ./test/testdata/policy-controller/e2e/cip-include-spec.yaml # allow things to propagate sleep 5 echo '::endgroup::' echo '::group:: test job success' # This one should pass since the serviceAccount is what we specified in the CIP # policy. Note that we run this as a pod since that's the spec that our cue # is looking for. if ! kubectl run -n ${NS} demo --image=${demoimage} ; then echo Failed to create Job in namespace with valid CIP policy! exit 1 else echo Succcessfully created Pod with correct serviceAccount fi echo '::endgroup::' echo '::group::' Cleanup kubectl delete cip --all kubectl delete ns ${NS} echo '::endgroup::' ================================================ FILE: test/e2e_test_cluster_image_policy_with_include_typemeta.sh ================================================ #!/usr/bin/env bash # # 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. #set -ex set -e # This is a timestamp server that we just use for testing evaluating CIP level # policy validations. export demoimage="ghcr.io/sigstore/timestamp-server@sha256:dcf2f3a640bfb0a5d17aabafb34b407fe4403363c715718ab305a62b3606540d" # To simplify testing failures, use this function to execute a kubectl to create # our pod and verify that the failure is expected. Note that this sets a label # that we expect to fail assert_error() { local KUBECTL_OUT_FILE="/tmp/kubectl.failure.out" match="$@" echo looking for ${match} kubectl delete job job-that-fails -n ${NS} --ignore-not-found=true if kubectl create -n ${NS} job job-that-fails --image=${demoimage} 2> ${KUBECTL_OUT_FILE} ; then echo Failed to block expected Job failure! exit 1 else echo Successfully blocked Job creation with expected error: "${match}" if ! grep -q "${match}" ${KUBECTL_OUT_FILE} ; then echo Did not get expected failure message, wanted "${match}", got cat ${KUBECTL_OUT_FILE} exit 1 fi fi } echo '::group:: Create test namespace and label for verification' kubectl create namespace demo-include-typemeta kubectl label namespace demo-include-typemeta policy.sigstore.dev/include=true export NS=demo-include-typemeta echo '::endgroup::' # Note that we put this in a for loop to make sure the webhook is actually # up and running before proceeding with the tests. echo '::group:: Deploy ClusterImagePolicy with our CIP that only allows Pods' for i in {1..10} do if kubectl apply -f ./test/testdata/policy-controller/e2e/cip-include-typemeta.yaml ; then echo successfully applied failing CIP break fi if [ "$i" == 10 ]; then echo failed to apply Pod only CIP exit 1 fi echo failed to apply Pod only CIP. Attempt numer "$i", retrying sleep 2 done # allow things to propagate sleep 5 echo '::endgroup::' echo '::group:: validate failure that can not run Jobs' expected_error='failed evaluating cue policy for ClusterImagePolicy: failed to evaluate the policy with error: typemeta.kind: conflicting values "Job" and "Pod"' assert_error ${expected_error} echo '::endgroup::' echo '::group:: test pod success' # This one should pass since the label is what we specified in the CIP # policy. if ! kubectl run -n ${NS} demo --image=${demoimage} ; then echo Failed to create Pod in namespace with valid CIP policy! exit 1 else echo Succcessfully created Pod fi echo '::endgroup::' echo '::group::' Cleanup kubectl delete -n ${NS} pods --all kubectl delete cip --all kubectl delete ns ${NS} echo '::endgroup::' ================================================ FILE: test/e2e_test_cluster_image_policy_with_oci11_attestations.sh ================================================ #!/usr/bin/env bash # # Copyright 2025 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. # This test validates that the policy controller can discover and verify # attestations stored using the OCI 1.1 referrers API (as opposed to the # legacy tag-based discovery). Google Cloud Build stores attestations this way. set -ex # Use a public image with OCI 1.1 attestations from Google Cloud Build # This image has attestations discoverable via the OCI 1.1 referrers API export TEST_IMAGE="us-docker.pkg.dev/cloudrun/container/hello@sha256:ee5d02305108fd8d65a8299a26cf01b6f976986fd04062e31280f97f21a91e3d" # Namespace for testing export NS="demo-oci11-attest" echo '::group:: Create test namespace' kubectl create namespace ${NS} echo '::endgroup::' echo '::group:: Enable OCI 1.1 support in policy controller' kubectl patch configmap/config-policy-controller \ --namespace cosign-system \ --type merge \ --patch '{"data":{"enable-oci11":"true"}}' # Allow for propagation sleep 5 echo '::endgroup::' echo '::group:: Create ClusterImagePolicy for OCI 1.1 attestations' # This policy uses a static key (Google Cloud Build public key) to verify # attestations discoverable via OCI 1.1 referrers API kubectl apply -f - < main.go package main import "fmt" func main() { fmt.Println("hello world TIMESTAMP") } EOF # To simplify testing failures, use this function to execute a kubectl to create # our job and verify that the failure is expected. assert_error() { local KUBECTL_OUT_FILE="/tmp/kubectl.failure.out" match="$@" echo looking for ${match} kubectl delete job demo -n demo-keyless-source --ignore-not-found=true if kubectl create -n demo-keyless-source job demo --image=${demoimage} 2> ${KUBECTL_OUT_FILE} ; then echo Failed to block expected Job failure! exit 1 else echo Successfully blocked Job creation with expected error: "${match}" if ! grep -q "${match}" ${KUBECTL_OUT_FILE} ; then echo Did not get expected failure message, wanted "${match}", got cat ${KUBECTL_OUT_FILE} exit 1 fi fi } sed -i'' -e "s@TIMESTAMP@${TIMESTAMP}@g" main.go cat main.go export demoimage=`ko publish -B example.com/demo` echo Created image $demoimage popd echo '::endgroup::' echo '::group:: Deploy ClusterImagePolicy with keyless signing and source' kubectl apply -f ./test/testdata/policy-controller/e2e/cip-keyless-with-source.yaml echo '::endgroup::' echo '::group:: Sign demo image' cosign sign --rekor-url ${REKOR_URL} --fulcio-url ${FULCIO_URL} --yes --allow-insecure-registry ${demoimage} --identity-token ${OIDC_TOKEN} echo '::endgroup::' echo '::group:: Verify demo image' cosign verify --rekor-url ${REKOR_URL} --allow-insecure-registry --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage} echo '::endgroup::' echo '::group:: Create test namespace and label for verification' kubectl create namespace demo-keyless-source kubectl label namespace demo-keyless-source policy.sigstore.dev/include=true export NS=demo-keyless-source echo '::endgroup::' echo '::group:: test job success as source.oci points to the right repository' # We signed this above, this should work if ! kubectl create -n demo-keyless-source job demo --image=${demoimage} ; then echo Failed to create Job in namespace with matching signature and good OCI source! exit 1 else echo Succcessfully created Job with signed image and good OCI source fi echo '::endgroup::' echo '::group:: Change source.oci in policy to a wrong repository without signatures' kubectl patch cip image-policy-keyless-source --type "json" \ -p '[{"op":"replace", "path":"/spec/authorities/0/source/0/oci", "value":"ghcr.io/sigstore/cosign/cosign"}]' # allow for propagation sleep 5 echo '::endgroup::' echo '::group:: test job rejection using an OCI source to a wrong repository without signatures' expected_error='no signatures found' assert_error ${expected_error} echo '::endgroup::' echo '::group:: Remove the old CIP and create CIP that uses attestation with prefixes' kubectl delete cip --all kubectl apply -f ./test/testdata/policy-controller/e2e/cip-keyless-with-source-prefix-tag.yaml # allow for propagation sleep 5 echo '::endgroup::' echo '::group:: Create an attestation without prefix, make sure it fails' echo -n 'foobar prefix e2e test' > ./predicate-file-prefix-custom cosign attest --predicate ./predicate-file-prefix-custom --rekor-url ${REKOR_URL} --allow-insecure-registry --yes ${demoimage} --fulcio-url ${FULCIO_URL} --identity-token ${OIDC_TOKEN} cosign verify-attestation --allow-insecure-registry --rekor-url ${REKOR_URL} --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage} echo '::endgroup::' echo '::group:: test job rejection using an OCI source to a wrong repository without signatures' expected_error='no matching attestations' assert_error ${expected_error} echo '::endgroup::' echo '::group:: Create an attestation with prefix, make sure it fails' cosign attest --predicate ./predicate-file-prefix-custom --rekor-url ${REKOR_URL} --allow-insecure-registry --yes ${demoimage} --attachment-tag-prefix=sigprefix --fulcio-url ${FULCIO_URL} --identity-token ${OIDC_TOKEN} cosign verify-attestation --allow-insecure-registry --rekor-url ${REKOR_URL} --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage} --attachment-tag-prefix=sigprefix echo '::endgroup::' echo '::group:: test job success since we have attestation with prefix' # We signed this above, this should work if ! kubectl create -n demo-keyless-source job demo --image=${demoimage} ; then echo Failed to create Job in namespace with matching attestation with prefix! exit 1 else echo Succcessfully created Job with attestation with prefix fi echo '::endgroup::' echo '::group::' Cleanup kubectl delete cip --all kubectl delete ns ${NS} echo '::endgroup::' ================================================ FILE: test/e2e_test_cluster_image_policy_with_trustroot_bring_own_keys.sh ================================================ #!/usr/bin/env bash # # 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. set -ex if [[ -z "${OIDC_TOKEN}" ]]; then if [[ -z "${ISSUER_URL}" ]]; then echo "Must specify either env variable OIDC_TOKEN or ISSUER_URL" exit 1 else export OIDC_TOKEN=`curl -s ${ISSUER_URL}` fi fi if [[ -z "${KO_DOCKER_REPO}" ]]; then echo "Must specify env variable KO_DOCKER_REPO" exit 1 fi if [[ -z "${FULCIO_URL}" ]]; then echo "Must specify env variable FULCIO_URL" exit 1 fi if [[ -z "${REKOR_URL}" ]]; then echo "Must specify env variable REKOR_URL" exit 1 fi if [[ -z "${TUF_ROOT_FILE}" ]]; then echo "must specify env variable TUF_ROOT_FILE" exit 1 fi if [[ -z "${TUF_MIRROR}" ]]; then echo "must specify env variable TUF_MIRROR" exit 1 fi if [[ "${NON_REPRODUCIBLE}"=="1" ]]; then echo "creating non-reproducible build by adding a timestamp" export TIMESTAMP=`date +%s` else export TIMESTAMP="TIMESTAMP" fi # Initialize cosign with our TUF root cosign initialize --mirror ${TUF_MIRROR} --root ${TUF_ROOT_FILE} # To simplify testing failures, use this function to execute a kubectl to create # our job and verify that the failure is expected. assert_error() { local KUBECTL_OUT_FILE="/tmp/kubectl.failure.out" match="$@" echo looking for ${match} kubectl delete job demo -n ${NS} --ignore-not-found=true if kubectl create -n ${NS} job demo --image=${demoimage} 2> ${KUBECTL_OUT_FILE} ; then echo Failed to block expected Job failure! exit 1 else echo Successfully blocked Job creation with expected error: "${match}" if ! grep -q "${match}" ${KUBECTL_OUT_FILE} ; then echo Did not get expected failure message, wanted "${match}", got cat ${KUBECTL_OUT_FILE} exit 1 fi fi } # Publish test image echo '::group:: publish test image demoimage' pushd $(mktemp -d) go mod init example.com/demo cat < main.go package main import "fmt" func main() { fmt.Println("hello world TIMESTAMP") } EOF sed -i'' -e "s@TIMESTAMP@${TIMESTAMP}@g" main.go cat main.go export demoimage=`ko publish -B example.com/demo` echo Created image $demoimage popd echo '::endgroup::' echo '::group:: Create and label new namespace for verification' kubectl create namespace demo-trustroot-bring-your-keys kubectl label namespace demo-trustroot-bring-your-keys policy.sigstore.dev/include=true export NS=demo-trustroot-bring-your-keys echo '::endgroup::' echo '::group:: Create CIP that requires keyless attestation with trustroot' kubectl apply -f ./test/testdata/policy-controller/e2e/cip-keyless-with-trustroot-with-attestations.yaml # allow things to propagate sleep 5 echo '::endgroup::' echo '::group:: Create TrustRoot that specifies Fulcio and Rekor certs/keys' export FULCIO_CERT_CHAIN=`kubectl -n tuf-system get secrets fulcio-pub-key -ojsonpath='{.data.cert}'` export REKOR_PUBLIC_KEY=`kubectl -n tuf-system get secrets rekor-pub-key -ojsonpath='{.data.public}'` export CTFE_PUBLIC_KEY=`kubectl -n tuf-system get secrets ctlog-public-key -ojsonpath='{.data.public}'` sed -i'' -e "s@FULCIO_CERT_CHAIN@${FULCIO_CERT_CHAIN}@g" ./test/testdata/trustroot/e2e/bring-your-own-keys.yaml sed -i'' -e "s@REKOR_PUBLIC_KEY@${REKOR_PUBLIC_KEY}@g" ./test/testdata/trustroot/e2e/bring-your-own-keys.yaml sed -i'' -e "s@CTFE_PUBLIC_KEY@${CTFE_PUBLIC_KEY}@g" ./test/testdata/trustroot/e2e/bring-your-own-keys.yaml kubectl apply -f ./test/testdata/trustroot/e2e/bring-your-own-keys.yaml # allow things to propagate sleep 5 echo '::endgroup::' # This image does not have an attestation, so should fail echo '::group:: test job rejection' expected_error='no matching attestations' assert_error ${expected_error} echo '::endgroup::' # Create attestation and it should pass. echo '::group:: Create one keyless attestation and verify it' echo -n 'foobar e2e test' > ./predicate-file-custom cosign attest --predicate ./predicate-file-custom --fulcio-url ${FULCIO_URL} --rekor-url ${REKOR_URL} --allow-insecure-registry --yes ${demoimage} --identity-token ${OIDC_TOKEN} cosign verify-attestation --type=custom --rekor-url ${REKOR_URL} --allow-insecure-registry --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage} echo '::endgroup::' echo '::group:: test job success' # We created keyless attestation, so should pass. export KUBECTL_SUCCESS_FILE="/tmp/kubectl.success.out" if ! kubectl create -n ${NS} job demo --image=${demoimage} 2> ${KUBECTL_SUCCESS_FILE} ; then echo Failed to create job with keyless attestation cat ${KUBECTL_SUCCESS_FILE} exit 1 else echo Created the job with keyless attestation fi kubectl delete -n ${NS} job demo echo '::endgroup::' echo '::group::' Cleanup kubectl delete cip --all kubectl delete trustroot --all kubectl delete ns ${NS} echo '::endgroup::' ================================================ FILE: test/e2e_test_cluster_image_policy_with_trustroot_remote.sh ================================================ #!/usr/bin/env bash # # 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. set -ex if [[ -z "${OIDC_TOKEN}" ]]; then if [[ -z "${ISSUER_URL}" ]]; then echo "Must specify either env variable OIDC_TOKEN or ISSUER_URL" exit 1 else export OIDC_TOKEN=`curl -s ${ISSUER_URL}` fi fi if [[ -z "${KO_DOCKER_REPO}" ]]; then echo "Must specify env variable KO_DOCKER_REPO" exit 1 fi if [[ -z "${FULCIO_URL}" ]]; then echo "Must specify env variable FULCIO_URL" exit 1 fi if [[ -z "${REKOR_URL}" ]]; then echo "Must specify env variable REKOR_URL" exit 1 fi if [[ -z "${TUF_ROOT_FILE}" ]]; then echo "must specify env variable TUF_ROOT_FILE" exit 1 fi if [[ -z "${TUF_MIRROR}" ]]; then echo "must specify env variable TUF_MIRROR" exit 1 fi if [[ "${NON_REPRODUCIBLE}"=="1" ]]; then echo "creating non-reproducible build by adding a timestamp" export TIMESTAMP=`date +%s` else export TIMESTAMP="TIMESTAMP" fi # Initialize cosign with our TUF root cosign initialize --mirror ${TUF_MIRROR} --root ${TUF_ROOT_FILE} # To simplify testing failures, use this function to execute a kubectl to create # our job and verify that the failure is expected. assert_error() { local KUBECTL_OUT_FILE="/tmp/kubectl.failure.out" match="$@" echo looking for ${match} kubectl delete job demo -n ${NS} --ignore-not-found=true if kubectl create -n ${NS} job demo --image=${demoimage} 2> ${KUBECTL_OUT_FILE} ; then echo Failed to block expected Job failure! exit 1 else echo Successfully blocked Job creation with expected error: "${match}" if ! grep -q "${match}" ${KUBECTL_OUT_FILE} ; then echo Did not get expected failure message, wanted "${match}", got cat ${KUBECTL_OUT_FILE} exit 1 fi fi } # Publish test image echo '::group:: publish test image demoimage' pushd $(mktemp -d) go mod init example.com/demo cat < main.go package main import "fmt" func main() { fmt.Println("hello world TIMESTAMP") } EOF sed -i'' -e "s@TIMESTAMP@${TIMESTAMP}@g" main.go cat main.go export demoimage=`ko publish -B example.com/demo` echo Created image $demoimage popd echo '::endgroup::' echo '::group:: Create and label new namespace for verification' kubectl create namespace demo-trustroot-remote kubectl label namespace demo-trustroot-remote policy.sigstore.dev/include=true export NS=demo-trustroot-remote echo '::endgroup::' echo '::group:: Create CIP that requires keyless attestation with trustroot' kubectl apply -f ./test/testdata/policy-controller/e2e/cip-keyless-with-trustroot-remote-with-attestations.yaml # allow things to propagate sleep 5 echo '::endgroup::' echo '::group:: Create TrustRoot that specifies remote with mirror' export ROOT_JSON=`kubectl -n tuf-system get secrets tuf-root -ojsonpath='{.data.root}'` sed -i'' -e "s@ROOT_JSON@${ROOT_JSON}@g" ./test/testdata/trustroot/e2e/with-remote.yaml sed -i'' -e "s@TUF_MIRROR@${TUF_MIRROR}@g" ./test/testdata/trustroot/e2e/with-remote.yaml kubectl apply -f ./test/testdata/trustroot/e2e/with-remote.yaml # allow things to propagate sleep 5 echo '::endgroup::' # This image has no attestation, so should fail echo '::group:: test job rejection' expected_error='no matching attestations' assert_error ${expected_error} echo '::endgroup::' # Create attestation and it should pass. echo '::group:: Create one keyless attestation and verify it' echo -n 'foobar e2e test' > ./predicate-file-custom cosign attest --predicate ./predicate-file-custom --fulcio-url ${FULCIO_URL} --rekor-url ${REKOR_URL} --allow-insecure-registry --yes ${demoimage} --identity-token ${OIDC_TOKEN} cosign verify-attestation --type=custom --rekor-url ${REKOR_URL} --allow-insecure-registry --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage} echo '::endgroup::' echo '::group:: test job success' # This has now a keyless attestation, so should pass. export KUBECTL_SUCCESS_FILE="/tmp/kubectl.success.out" if ! kubectl create -n ${NS} job demo --image=${demoimage} 2> ${KUBECTL_SUCCESS_FILE} ; then echo Failed to create job with keyless attestation cat ${KUBECTL_SUCCESS_FILE} exit 1 else echo Created the job with keyless attestation fi kubectl delete -n ${NS} job demo echo '::endgroup::' echo '::group::' Cleanup kubectl delete cip --all kubectl delete trustroot --all kubectl delete ns ${NS} echo '::endgroup::' ================================================ FILE: test/e2e_test_cluster_image_policy_with_trustroot_repository.sh ================================================ #!/usr/bin/env bash # # 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. set -ex if [[ -z "${OIDC_TOKEN}" ]]; then if [[ -z "${ISSUER_URL}" ]]; then echo "Must specify either env variable OIDC_TOKEN or ISSUER_URL" exit 1 else export OIDC_TOKEN=`curl -s ${ISSUER_URL}` fi fi if [[ -z "${KO_DOCKER_REPO}" ]]; then echo "Must specify env variable KO_DOCKER_REPO" exit 1 fi if [[ -z "${FULCIO_URL}" ]]; then echo "Must specify env variable FULCIO_URL" exit 1 fi if [[ -z "${REKOR_URL}" ]]; then echo "Must specify env variable REKOR_URL" exit 1 fi if [[ -z "${TUF_ROOT_FILE}" ]]; then echo "must specify env variable TUF_ROOT_FILE" exit 1 fi if [[ -z "${TUF_MIRROR}" ]]; then echo "must specify env variable TUF_MIRROR" exit 1 fi if [[ "${NON_REPRODUCIBLE}"=="1" ]]; then echo "creating non-reproducible build by adding a timestamp" export TIMESTAMP=`date +%s` else export TIMESTAMP="TIMESTAMP" fi # Initialize cosign with our TUF root cosign initialize --mirror ${TUF_MIRROR} --root ${TUF_ROOT_FILE} # To simplify testing failures, use this function to execute a kubectl to create # our job and verify that the failure is expected. assert_error() { local KUBECTL_OUT_FILE="/tmp/kubectl.failure.out" match="$@" echo looking for ${match} kubectl delete job demo -n ${NS} --ignore-not-found=true if kubectl create -n ${NS} job demo --image=${demoimage} 2> ${KUBECTL_OUT_FILE} ; then echo Failed to block expected Job failure! exit 1 else echo Successfully blocked Job creation with expected error: "${match}" if ! grep -q "${match}" ${KUBECTL_OUT_FILE} ; then echo Did not get expected failure message, wanted "${match}", got cat ${KUBECTL_OUT_FILE} exit 1 fi fi } # Publish test image echo '::group:: publish test image demoimage' pushd $(mktemp -d) go mod init example.com/demo cat < main.go package main import "fmt" func main() { fmt.Println("hello world TIMESTAMP") } EOF sed -i'' -e "s@TIMESTAMP@${TIMESTAMP}@g" main.go cat main.go export demoimage=`ko publish -B example.com/demo` echo Created image $demoimage popd echo '::endgroup::' echo '::group:: Create and label new namespace for verification' kubectl create namespace demo-trustroot-repository kubectl label namespace demo-trustroot-repository policy.sigstore.dev/include=true export NS=demo-trustroot-repository echo '::endgroup::' echo '::group:: Create CIP that requires keyless attestation with trustroot' kubectl apply -f ./test/testdata/policy-controller/e2e/cip-keyless-with-trustroot-repository-with-attestations.yaml # allow things to propagate sleep 5 echo '::endgroup::' echo '::group:: Create TrustRoot that specifies marshalled repository' export ROOT_JSON=`kubectl -n tuf-system get secrets tuf-root -ojsonpath='{.data.root}'` export REPOSITORY=`kubectl -n tuf-system get secrets tuf-root -ojsonpath='{.data.repository}'` sed -i'' -e "s@ROOT_JSON@${ROOT_JSON}@g" ./test/testdata/trustroot/e2e/with-repository.yaml sed -i'' -e "s@REPOSITORY@${REPOSITORY}@g" ./test/testdata/trustroot/e2e/with-repository.yaml kubectl apply -f ./test/testdata/trustroot/e2e/with-repository.yaml # allow things to propagate sleep 5 echo '::endgroup::' # This image has no attestation, so should fail echo '::group:: test job rejection' expected_error='no matching attestations' assert_error ${expected_error} echo '::endgroup::' # Create an attestation but do not add it to Rekor and since our attestation # specifies Rekor, this should still fail echo '::group:: Create one keyless attestation and verify it, but no tlog upload' echo -n 'foobar e2e test' > ./predicate-file-custom cosign attest --predicate ./predicate-file-custom --fulcio-url ${FULCIO_URL} --allow-insecure-registry ${demoimage} --tlog-upload=false --identity-token `curl $ISSUER_URL` cosign verify-attestation --insecure-ignore-tlog --type=custom --rekor-url= --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' --allow-insecure-registry ${demoimage} echo '::endgroup::' # This image has an attestation, but was not added to TLog echo '::group:: test job rejection' expected_error='signature not found in transparency log' assert_error ${expected_error} echo '::endgroup::' # Create attestation and upload to tlog and it should now pass. echo '::group:: Create one keyless attestation and verify it' cosign attest --predicate ./predicate-file-custom --fulcio-url ${FULCIO_URL} --rekor-url ${REKOR_URL} --allow-insecure-registry --yes ${demoimage} --identity-token ${OIDC_TOKEN} cosign verify-attestation --type=custom --rekor-url ${REKOR_URL} --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' --allow-insecure-registry ${demoimage} echo '::endgroup::' echo '::group:: test job success' # This now has a keyless attestation, so should pass. export KUBECTL_SUCCESS_FILE="/tmp/kubectl.success.out" if ! kubectl create -n ${NS} job demo --image=${demoimage} 2> ${KUBECTL_SUCCESS_FILE} ; then echo Failed to create job with keyless signature and an attestation cat ${KUBECTL_SUCCESS_FILE} exit 1 else echo Created the job with keyless signature and an attestation fi kubectl delete -n ${NS} job demo echo '::endgroup::' echo '::group::' Cleanup kubectl delete cip --all kubectl delete trustroot --all kubectl delete ns ${NS} echo '::endgroup::' ================================================ FILE: test/e2e_test_cluster_image_policy_with_tsa.sh ================================================ #!/usr/bin/env bash # # 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. set -ex if [[ -z "${OIDC_TOKEN}" ]]; then if [[ -z "${ISSUER_URL}" ]]; then echo "Must specify either env variable OIDC_TOKEN or ISSUER_URL" exit 1 else export OIDC_TOKEN=`curl -s ${ISSUER_URL}` fi fi if [[ -z "${KO_DOCKER_REPO}" ]]; then echo "Must specify env variable KO_DOCKER_REPO" exit 1 fi if [[ -z "${FULCIO_URL}" ]]; then echo "Must specify env variable FULCIO_URL" exit 1 fi if [[ -z "${REKOR_URL}" ]]; then echo "Must specify env variable REKOR_URL" exit 1 fi if [[ -z "${TUF_ROOT_FILE}" ]]; then echo "must specify env variable TUF_ROOT_FILE" exit 1 fi if [[ -z "${TUF_MIRROR}" ]]; then echo "must specify env variable TUF_MIRROR" exit 1 fi if [[ "${NON_REPRODUCIBLE}"=="1" ]]; then echo "creating non-reproducible build by adding a timestamp" export TIMESTAMP=`date +%s` else export TIMESTAMP="TIMESTAMP" fi # Initialize cosign with our TUF root cosign initialize --mirror ${TUF_MIRROR} --root ${TUF_ROOT_FILE} # To simplify testing failures, use this function to execute a kubectl to create # our job and verify that the failure is expected. assert_error() { local KUBECTL_OUT_FILE="/tmp/kubectl.failure.out" match="$@" echo looking for ${match} kubectl delete job demo -n ${NS} --ignore-not-found=true if kubectl create -n ${NS} job demo --image=${demoimage} 2> ${KUBECTL_OUT_FILE} ; then echo Failed to block expected Job failure! exit 1 else echo Successfully blocked Job creation with expected error: "${match}" if ! grep -q "${match}" ${KUBECTL_OUT_FILE} ; then echo Did not get expected failure message, wanted "${match}", got cat ${KUBECTL_OUT_FILE} exit 1 fi fi } # Publish test image echo '::group:: publish test image demoimage' pushd $(mktemp -d) go mod init example.com/demo cat < main.go package main import "fmt" func main() { fmt.Println("hello world TIMESTAMP") } EOF sed -i'' -e "s@TIMESTAMP@${TIMESTAMP}@g" main.go cat main.go export demoimage=`ko publish -B example.com/demo` echo Created image $demoimage popd echo '::endgroup::' echo '::group:: Create and label new namespace for verification' kubectl create namespace demo-tsa-remote kubectl label namespace demo-tsa-remote policy.sigstore.dev/include=true export NS=demo-tsa-remote echo '::endgroup::' echo '::group:: Generate New Signing Key that we use for key-ful signing' COSIGN_PASSWORD="" cosign generate-key-pair echo '::endgroup::' # Sign it with key echo '::group:: Sign demoimage with key, and add to rekor and TSA' export TSA_URL=`kubectl -n tsa-system get ksvc tsa -ojsonpath='{.status.url}'` export TSA_URL="${TSA_URL}/api/v1/timestamp" COSIGN_YES="true" COSIGN_PASSWORD="" cosign sign --key cosign.key --allow-insecure-registry --rekor-url ${REKOR_URL} --timestamp-server-url ${TSA_URL} ${demoimage} echo '::endgroup::' echo '::group:: Verify demoimage with cosign key and TSA' export TSA_CERT_CHAIN=`kubectl -n tsa-system get secrets tsa-cert-chain -ojsonpath='{.data.cert-chain}'` echo "$TSA_CERT_CHAIN" | base64 -d > tsa-cert-chain.pem cosign verify --key cosign.pub --timestamp-certificate-chain tsa-cert-chain.pem --insecure-ignore-tlog --rekor-url ${REKOR_URL} --allow-insecure-registry --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage} echo '::endgroup::' echo '::group:: Create TrustRoot that specifies TSA' cp ./test/testdata/trustroot/e2e/with-tsa.yaml ./with-tsa.yaml.bkp sed -i'' -e "s@TSA_CERT_CHAIN@${TSA_CERT_CHAIN}@g" ./test/testdata/trustroot/e2e/with-tsa.yaml sed -i'' -e "s@TSA_URL@${TSA_URL}@g" ./test/testdata/trustroot/e2e/with-tsa.yaml kubectl apply -f ./test/testdata/trustroot/e2e/with-tsa.yaml # allow things to propagate sleep 5 echo '::endgroup::' echo '::group:: Create CIP that requires a keyful and includes a TSA verification' yq '. | .spec.authorities[0].key.data |= load_str("cosign.pub")' ./test/testdata/policy-controller/e2e/cip-key-tsa.yaml | kubectl apply -f - # Give the policy controller a moment to update the configmap # and pick up the change in the admission controller. sleep 5 echo '::endgroup::' echo '::group:: test job success' # This has now a job signed and verified via a TSA, so should pass. export KUBECTL_SUCCESS_FILE="/tmp/kubectl.success.out" if ! kubectl create -n ${NS} job demo --image=${demoimage} 2> ${KUBECTL_SUCCESS_FILE} ; then echo Failed to create job with a TSA verification cat ${KUBECTL_SUCCESS_FILE} exit 1 else echo Created the job with a TSA verification fi kubectl delete -n ${NS} job demo echo '::endgroup::' # Publish the second test image echo '::group:: publish test image demoimage' pushd $(mktemp -d) go mod init example.com/demo cat < main.go package main import "fmt" func main() { fmt.Println("hello world 2 TIMESTAMP") } EOF sed -i'' -e "s@TIMESTAMP@${TIMESTAMP}@g" main.go cat main.go export demoimage2=`ko publish -B example.com/demo` popd echo '::endgroup::' # Sign it with key echo '::group:: Sign demoimage2 with key, and add to rekor and TSA' export TSA_URL=`kubectl -n tsa-system get ksvc tsa -ojsonpath='{.status.url}'` # Cosign TSA integration now requires passing the API endpoint URL export TSA_URL="${TSA_URL}/api/v1/timestamp" COSIGN_YES="true" COSIGN_PASSWORD="" cosign sign --key cosign.key --allow-insecure-registry --rekor-url ${REKOR_URL} --timestamp-server-url ${TSA_URL} ${demoimage2} echo '::endgroup::' echo '::group:: Verify demoimage2 with cosign key and TSA' export TSA_CERT_CHAIN=`kubectl -n tsa-system get secrets tsa-cert-chain -ojsonpath='{.data.cert-chain}'` echo "$TSA_CERT_CHAIN" | base64 -d > tsa-cert-chain.pem cosign verify --key cosign.pub --timestamp-certificate-chain tsa-cert-chain.pem --insecure-ignore-tlog --allow-insecure-registry --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage2} echo '::endgroup::' echo '::group:: Change Certificate chain of TrustRoot to a wrong one for our TSA' cp ./with-tsa.yaml.bkp ./test/testdata/trustroot/e2e/with-tsa.yaml # This certificate chain belongs a different TSA server so any verification should fail export TSA_CERT_CHAIN="LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJ6RENDQVhLZ0F3SUJBZ0lVWFBCNWVWRWhZcVBPaEk0dE45ak4wM1ZkUW5rd0NnWUlLb1pJemowRUF3SXcKTURFT01Bd0dBMVVFQ2hNRmJHOWpZV3d4SGpBY0JnTlZCQU1URlZSbGMzUWdWRk5CSUVsdWRHVnliV1ZrYVdGMApaVEFlRncweU1qRXhNakV4TVRVNE1UaGFGdzB6TVRFeE1qRXhNakF4TVRoYU1EQXhEakFNQmdOVkJBb1RCV3h2ClkyRnNNUjR3SEFZRFZRUURFeFZVWlhOMElGUlRRU0JVYVcxbGMzUmhiWEJwYm1jd1dUQVRCZ2NxaGtqT1BRSUIKQmdncWhrak9QUU1CQndOQ0FBVEhvRUE3b05URWJDcjVxdnd6STlsN0ZJaHNqQlFnUDhGbFhEeFNDaFdYVDJZNQpMWDhQVlFYTHJFbHhNVzJ0dnk0SjQzdTJCRG9JQ1hHeW5xZ1pWMlBmbzJvd2FEQU9CZ05WSFE4QkFmOEVCQU1DCkI0QXdIUVlEVlIwT0JCWUVGQis4WEx2TTlWU3pyUmdFQiswOUZrdlhmYVM2TUI4R0ExVWRJd1FZTUJhQUZDWUIKSEc1eDVDVE9YLytueVlsanltWVZQT3ZqTUJZR0ExVWRKUUVCL3dRTU1Bb0dDQ3NHQVFVRkJ3TUlNQW9HQ0NxRwpTTTQ5QkFNQ0EwZ0FNRVVDSUFJd1IwMG5xRS96cG5OSEozY3VoWTRRZjEzTkd3anhUOTBSUWhxSjFNZlpBaUVBCm9lclFGQWVGYnZYU3VLTFdXK2lsdEh2dEsyUUF1VXZub1ZnZ0tCYzhpSTg9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0KLS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUIwakNDQVhpZ0F3SUJBZ0lVVXgvd3NrMFNhVU5ZcUtKWEtLMlpyMmYzZlJFd0NnWUlLb1pJemowRUF3SXcKS0RFT01Bd0dBMVVFQ2hNRmJHOWpZV3d4RmpBVUJnTlZCQU1URFZSbGMzUWdWRk5CSUZKdmIzUXdIaGNOTWpJeApNVEl4TVRFMU5qRTRXaGNOTXpJeE1USXhNVEl3TVRFNFdqQXdNUTR3REFZRFZRUUtFd1ZzYjJOaGJERWVNQndHCkExVUVBeE1WVkdWemRDQlVVMEVnU1c1MFpYSnRaV1JwWVhSbE1Ga3dFd1lIS29aSXpqMENBUVlJS29aSXpqMEQKQVFjRFFnQUVvUysxNFNXTmUxc2hwc280cERFMEhTNjZqdmYyenlJUS9jcHRuM2pyUTAyelJYZWQ5THBWS1A3YwpJbEVXWWNSaWw0anNXUkFsMU9zVjk4eGNFTUpvaktONE1IWXdEZ1lEVlIwUEFRSC9CQVFEQWdFR01CTUdBMVVkCkpRUU1NQW9HQ0NzR0FRVUZCd01JTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkNZQkhHNXgKNUNUT1gvK255WWxqeW1ZVlBPdmpNQjhHQTFVZEl3UVlNQmFBRkYxWEFHbW4xQXdtdFk0L0RGVWQ4RzhkTFRIMQpNQW9HQ0NxR1NNNDlCQU1DQTBnQU1FVUNJUUNoZTVTWVpsbVNWeXczczJOcDRQNE5FS1l0ODc4RGZ6M3JlRlZKCkVHemxJd0lnUEc4bHlaYXdLOWo2c3BlTHFtUy9Hei9LdjJJQ3FsSy9XOEFzNGN1OEtuRT0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJQmxUQ0NBVHFnQXdJQkFnSVVQY2NwVS95TUJkNmViMzM1YlZSOTZwTGZNQWN3Q2dZSUtvWkl6ajBFQXdJdwpLREVPTUF3R0ExVUVDaE1GYkc5allXd3hGakFVQmdOVkJBTVREVlJsYzNRZ1ZGTkJJRkp2YjNRd0hoY05Nakl4Ck1USXhNVEUxTmpFNFdoY05Nekl4TVRJeE1USXdNVEU0V2pBb01RNHdEQVlEVlFRS0V3VnNiMk5oYkRFV01CUUcKQTFVRUF4TU5WR1Z6ZENCVVUwRWdVbTl2ZERCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQklUWgpqZnVhTGJXbjloYjhtNVVabmtrcUs5K3dQam92b0F3VCtPQWRTK0kzZlptTFRnamdoMW8vUHhtb0UvT2RuOUtOCmtxcnVKWkJuaWQwb0VVT3BwWE9qUWpCQU1BNEdBMVVkRHdFQi93UUVBd0lCQmpBUEJnTlZIUk1CQWY4RUJUQUQKQVFIL01CMEdBMVVkRGdRV0JCUmRWd0JwcDlRTUpyV09Qd3hWSGZCdkhTMHg5VEFLQmdncWhrak9QUVFEQWdOSgpBREJHQWlFQWhFdW9xQ2JaRDA5bmx2WjNtcFJiR0paZFg0Nm1rUFUrVFFpUklFT2l5NGdDSVFEakRBWDdxT0x0Cm5RVEVrRGcwcklBU0hqaVVNTk5tRVFqTlZmaDlDMEx3OXc9PQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0t" sed -i'' -e "s@TSA_CERT_CHAIN@${TSA_CERT_CHAIN}@g" ./test/testdata/trustroot/e2e/with-tsa.yaml sed -i'' -e "s@TSA_URL@${TSA_URL}@g" ./test/testdata/trustroot/e2e/with-tsa.yaml kubectl apply -f ./test/testdata/trustroot/e2e/with-tsa.yaml # allow things to propagate sleep 10 echo '::endgroup::' # We did sign this, but should fail due to a different certificate chain for the TSA verification echo '::group:: test job rejection with TSA using a different cert-chain' if kubectl create -n ${NS} job demo2 --image=${demoimage2} ; then echo Failed to block Job creation when TSA verification fails! exit 1 else echo Successfully blocked Job creation with TSA using a different certificate chain fi echo '::endgroup::' echo '::group::' Cleanup kubectl delete cip --all kubectl delete trustroot --all kubectl delete ns ${NS} echo '::endgroup::' ================================================ FILE: test/e2e_test_cluster_image_policy_with_warn.sh ================================================ #!/usr/bin/env bash # # 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. set -ex if [[ -z "${OIDC_TOKEN}" ]]; then if [[ -z "${ISSUER_URL}" ]]; then echo "Must specify either env variable OIDC_TOKEN or ISSUER_URL" exit 1 else export OIDC_TOKEN=`curl -s ${ISSUER_URL}` fi fi if [[ -z "${KO_DOCKER_REPO}" ]]; then echo "Must specify env variable KO_DOCKER_REPO" exit 1 fi if [[ -z "${FULCIO_URL}" ]]; then echo "Must specify env variable FULCIO_URL" exit 1 fi if [[ -z "${REKOR_URL}" ]]; then echo "Must specify env variable REKOR_URL" exit 1 fi if [[ -z "${TUF_ROOT_FILE}" ]]; then echo "must specify env variable TUF_ROOT_FILE" exit 1 fi if [[ -z "${TUF_MIRROR}" ]]; then echo "must specify env variable TUF_MIRROR" exit 1 fi if [[ "${NON_REPRODUCIBLE}"=="1" ]]; then echo "creating non-reproducible build by adding a timestamp" export TIMESTAMP=`date +%s` else export TIMESTAMP="TIMESTAMP" fi # Initialize cosign with our TUF root cosign initialize --mirror ${TUF_MIRROR} --root ${TUF_ROOT_FILE} # To simplify testing warnings, use this function to execute a kubectl to create # our job and verify that the warning is as expected. assert_warning() { local KUBECTL_OUT_FILE="/tmp/kubectl.warning.out" match="$@" echo looking for ${match} kubectl delete job job-that-warns -n ${NS} --ignore-not-found=true if ! kubectl create -n ${NS} job job-that-warns --image=${demoimage2} 2> ${KUBECTL_OUT_FILE} ; then echo Failed to create Job when expected to warn! exit 1 else echo Successfully created job, checking warning: "${match}" if ! grep -q "${match}" ${KUBECTL_OUT_FILE} ; then echo Did not get expected warning message, wanted "${match}", got cat ${KUBECTL_OUT_FILE} exit 1 fi fi } # Publish the first test image echo '::group:: publish test image demoimage' pushd $(mktemp -d) go mod init example.com/demo cat < main.go package main import "fmt" func main() { fmt.Println("hello world TIMESTAMP") } EOF sed -i'' -e "s@TIMESTAMP@${TIMESTAMP}@g" main.go cat main.go export demoimage=`ko publish -B example.com/demo` echo Created image $demoimage popd echo '::endgroup::' # Publish the second test image echo '::group:: publish test image demoimage' pushd $(mktemp -d) go mod init example.com/demo cat < main.go package main import "fmt" func main() { fmt.Println("hello world 2 TIMESTAMP") } EOF sed -i'' -e "s@TIMESTAMP@${TIMESTAMP}@g" main.go cat main.go export demoimage2=`ko publish -B example.com/demo` popd echo '::endgroup::' echo '::group:: Deploy ClusterImagePolicy with keyless signing' kubectl apply -f ./test/testdata/policy-controller/e2e/cip-keyless-warn.yaml echo '::endgroup::' echo '::group:: Sign demo image' cosign sign --rekor-url ${REKOR_URL} --fulcio-url ${FULCIO_URL} --yes --allow-insecure-registry ${demoimage} --identity-token ${OIDC_TOKEN} echo '::endgroup::' echo '::group:: Verify demo image' cosign verify --rekor-url ${REKOR_URL} --allow-insecure-registry --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage} echo '::endgroup::' echo '::group:: Create test namespace and label for verification' kubectl create namespace demo-keyless-signing kubectl label namespace demo-keyless-signing policy.sigstore.dev/include=true export NS=demo-keyless-signing echo '::endgroup::' echo '::group:: test job success' # We signed this above, this should work if ! kubectl create -n demo-keyless-signing job demo --image=${demoimage} ; then echo Failed to create Job in namespace with matching signature! exit 1 else echo Succcessfully created Job with signed image fi echo '::endgroup::' # We did not sign this, should warn but not fail echo '::group:: test job admission with warning' expected_warn='Warning: failed policy: image-policy-keyless-warn' assert_warning ${expected_warn} echo '::endgroup::' # Change to an image that does not match any policies demoimage2="quay.io/jetstack/cert-manager-acmesolver:v1.9.1" # Then test the unmatched policy behaviour with default, which is deny echo '::group:: test no-match default policy, which is deny' if kubectl create -n demo-keyless-signing job demo-should-not-work --image=${demoimage2} ; then echo Failed to block Job with no matching policy and default deny exit 1 else echo Successfully blocked Job in namespace with no matching policies, and deny fi echo '::endgroup::' echo '::group:: Change no-match policy to warn' kubectl patch configmap/config-policy-controller \ --namespace cosign-system \ --type merge \ --patch '{"data":{"no-match-policy":"warn"}}' # allow for propagation sleep 5 echo '::endgroup::' echo '::group:: test job admission with warning' expected_warn='Warning: no matching policies:' assert_warning ${expected_warn} echo '::endgroup::' echo '::group:: Change no-match policy to allow' kubectl patch configmap/config-policy-controller \ --namespace cosign-system \ --type merge \ --patch '{"data":{"no-match-policy":"allow"}}' # allow for propagation sleep 5 echo '::endgroup::' echo '::group:: test no-match policy allow' if ! kubectl create -n demo-keyless-signing job demo-works --image=${demoimage2} ; then echo Failed to create Job in namespace with no matching policies, but allow exit 1 else echo Succcessfully created Job because no matching policy and allow fi echo '::endgroup::' echo '::group::' Cleanup kubectl delete cip --all kubectl delete ns ${NS} echo '::endgroup::' ================================================ FILE: test/e2e_test_cluster_with_scalable.sh ================================================ #!/usr/bin/env bash # # 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. set -ex if [[ -z "${OIDC_TOKEN}" ]]; then if [[ -z "${TOKEN_ISSUER}" ]]; then echo "Must specify either env variable OIDC_TOKEN or TOKEN_ISSUER" exit 1 else export OIDC_TOKEN=`curl -s ${ISSUER_URL}` fi fi if [[ -z "${KO_DOCKER_REPO}" ]]; then echo "Must specify env variable KO_DOCKER_REPO" exit 1 fi if [[ -z "${FULCIO_URL}" ]]; then echo "Must specify env variable FULCIO_URL" exit 1 fi if [[ -z "${REKOR_URL}" ]]; then echo "Must specify env variable REKOR_URL" exit 1 fi if [[ -z "${TUF_ROOT_FILE}" ]]; then echo "must specify env variable TUF_ROOT_FILE" exit 1 fi if [[ -z "${TUF_MIRROR}" ]]; then echo "must specify env variable TUF_MIRROR" exit 1 fi if [[ "${NON_REPRODUCIBLE}"=="1" ]]; then echo "creating non-reproducible build by adding a timestamp" export TIMESTAMP=`date +%s` else export TIMESTAMP="TIMESTAMP" fi # Initialize cosign with our TUF root cosign initialize --mirror ${TUF_MIRROR} --root ${TUF_ROOT_FILE} # To simplify testing failures, use this function to execute a kubectl to scale # deployment up and verify that the failure is expected. assert_error() { local KUBECTL_OUT_FILE="/tmp/kubectl.failure.out" match="$@" echo looking for ${match} if kubectl patch -n ${NS} deployment test-deployment --type "json" -p '[{"op":"replace", "path":"/spec/replicas", "value":5}]' 2> ${KUBECTL_OUT_FILE} ; then echo Failed to block expected scaling failure! exit 1 else echo Successfully blocked scaling with expected error: "${match}" if ! grep -q "${match}" ${KUBECTL_OUT_FILE} ; then echo Did not get expected failure message, wanted "${match}", got cat ${KUBECTL_OUT_FILE} exit 1 fi fi } # Publish test image echo '::group:: publish test image demoimage' pushd $(mktemp -d) go mod init example.com/demo cat < main.go package main import ( "fmt" "time" ) func main() { fmt.Println("hello world deployment TIMESTAMP") time.Sleep(10*time.Minute) } EOF sed -i'' -e "s@TIMESTAMP@${TIMESTAMP}@g" main.go cat main.go export demoimage=`ko publish -B example.com/demo` echo Created image $demoimage popd echo '::endgroup::' echo '::group:: Create test namespace but do not label for verification' kubectl create namespace demo-scalable export NS=demo-scalable echo '::endgroup::' echo '::group:: Deploy deployment with unsigned image' sed "s#TEST_IMAGE#${demoimage}#" ./test/testdata/policy-controller/e2e/test-deployment.yaml | kubectl apply -f - echo '::endgroup::' echo '::group:: Label test namespace for verification' kubectl label namespace ${NS} policy.sigstore.dev/include=true echo '::endgroup::' echo '::group:: Deploy ClusterImagePolicy with keyless signing' kubectl apply -f ./test/testdata/policy-controller/e2e/cip-keyless.yaml # Give the policy controller a moment to update the configmap # and pick up the change in the admission controller. sleep 5 echo '::endgroup::' echo '::group:: Try to scale the Deployment up - should fail' expected_error="failed policy: image-policy-keyless: spec.template.spec.containers" assert_error ${expected_error} echo '::endgroup::' echo '::group:: Try to scale the Deployment down - should work' if ! kubectl patch -n ${NS} deployment test-deployment --type "json" -p '[{"op":"replace", "path":"/spec/replicas", "value":1}]' ; then echo Failed to scale down exit 1 fi echo '::endgroup::' echo '::group:: Sign demo image' cosign sign --rekor-url ${REKOR_URL} --fulcio-url ${FULCIO_URL} --yes --allow-insecure-registry ${demoimage} --identity-token ${OIDC_TOKEN} echo '::endgroup::' echo '::group:: Verify demo image' cosign verify --rekor-url ${REKOR_URL} --allow-insecure-registry --certificate-identity-regexp='.*' --certificate-oidc-issuer-regexp='.*' ${demoimage} echo '::endgroup::' echo '::group:: Try to scale the Deployment up - should work' if ! kubectl patch -n ${NS} deployment test-deployment --type "json" -p '[{"op":"replace", "path":"/spec/replicas", "value":5}]' ; then echo Failed to scale up with signed image exit 1 fi echo '::endgroup::' echo '::group::' Cleanup kubectl delete cip --all kubectl delete ns ${NS} echo '::endgroup::' ================================================ FILE: test/e2e_test_policy_controller.sh ================================================ #!/usr/bin/env bash # # Copyright 2021 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 echo '::group:: publish test image' DIGEST=$(ko publish -B ./cmd/sample) cat > pod.yaml < distroless-pod.yaml < job.yaml < cronjob.yaml < ${err_file}; then echo "${i} policy created when it should not have" exit 1 else for expected_error in ${expected_errors} do echo looking for error: ${expected_error} if ! grep --fixed-strings -q "${expected_error}" ${err_file} ; then echo Did not get expected failure message, wanted "${expected_error}", got cat ${err_file} exit 1 else echo "${i} rejected as expected" fi done fi done echo '::endgroup:: Invalid policy test:' echo '::group:: Warning policy tests:' for i in `ls ./test/testdata/policy-controller/warn/` do echo Testing: $i # Grab the expected error from the CIP expected_warnings=$(grep Warning: test/testdata/policy-controller/warn/${i} | cut -d ' ' -f 2-) warn_file="./kubectl_warn" if ! kubectl create -f ./test/testdata/policy-controller/warn/$i 2> ${warn_file}; then echo "${i} policy rejected when it should have only warned" cat ${warn_file} exit 1 else for expected_warning in ${expected_warnings} do echo looking for warning: ${expected_warning} if ! grep --fixed-strings -q "${expected_warning}" ${warn_file} ; then echo Did not get expected warning message, wanted "${expected_warning}", got cat ${warn_file} exit 1 else echo "${i} created and warning found as expected" fi done fi kubectl delete -f ./test/testdata/policy-controller/warn/$i --ignore-not-found=true done echo '::endgroup:: Warning policy test:' echo '::group:: Valid policy test:' for i in `ls ./test/testdata/policy-controller/valid/` do if kubectl create -f ./test/testdata/policy-controller/valid/$i ; then echo "${i} created as expected" else echo "${i} failed when it should not have" exit 1 fi kubectl delete -f ./test/testdata/policy-controller/valid/$i --ignore-not-found=true done echo '::endgroup:: Valid policy test:' echo '::group:: Set fail-on-empty-authorities to false' kubectl patch configmap/config-policy-controller \ --namespace cosign-system \ --type merge \ --patch '{"data":{"no-match-policy":"deny", "fail-on-empty-authorities":"false"}}' # allow for propagation sleep 10 echo '::endgroup::' echo '::group:: Empty authorities policies:' for i in `ls ./test/testdata/policy-controller/empty-authorities/` do if kubectl create -f ./test/testdata/policy-controller/empty-authorities/$i ; then echo "${i} created as expected" else echo "${i} failed when it should not have" exit 1 fi kubectl delete -f ./test/testdata/policy-controller/empty-authorities/$i --ignore-not-found=true done echo '::endgroup::' echo '::group:: Set fail-on-empty-authorities to true' kubectl patch configmap/config-policy-controller \ --namespace cosign-system \ --type merge \ --patch '{"data":{"no-match-policy":"deny", "fail-on-empty-authorities":"true"}}' # allow for propagation sleep 10 echo '::endgroup::' ================================================ FILE: test/e2e_test_trustroot_crd.sh ================================================ #!/usr/bin/env bash # # 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. set -o errexit set -o nounset set -o pipefail # This script will validate an e2e for given TrustRoot resources and validate # that they get reconciled correctly into the ConfigMap. For now we only # validate the keys/certs but we can add more tests. Reasoning being that the # certs/keys are the trickiest (I think) so let's start there. # The golden files live in the ./test/testdata/trustroot/golden where # rekor.pem is the public key for the TLog[0].PublicKey # ctfe.pem is the public key for the CTLog[0].PublicKey # fulcio.crt.pem is the certchain for the CertificateAuthority[0].CertChain # tsa.crt.pem is the certchain for the TimeStampAuthorities[0].CertChain # So we diff against those. echo '::group:: Create a TrustRoot with bring your own keys:' kubectl create -f ./test/testdata/trustroot/valid/valid-sigstore-keys.yaml # Allow for changes to propagate to ConfigMap sleep 5 echo '::endgroup::' echo '::group:: Validating the configmap entries' echo "Validating Fulcio entry" echo -n > ./got.fulcio.pem for cert in $(kubectl -n cosign-system get cm config-sigstore-keys -ojsonpath='{.data.bring-your-own-sigstore-keys}' | yq '.certificateAuthorities[0].certChain.certificates[] | .rawBytes' ); do echo $cert | base64 -d | openssl x509 -inform der >> ./got.fulcio.pem done diff ./got.fulcio.pem ./test/testdata/trustroot/golden/fulcio.crt.pem echo "Validating TSA entry" echo -n > ./got.tsa.pem for cert in $(kubectl -n cosign-system get cm config-sigstore-keys -ojsonpath='{.data.bring-your-own-sigstore-keys}' | yq '.timestampAuthorities[0].certChain.certificates[] | .rawBytes' ); do echo $cert | base64 -d | openssl x509 -inform der >> ./got.tsa.pem done diff ./got.tsa.pem ./test/testdata/trustroot/golden/tsa.crt.pem echo "Validating Rekor entry" kubectl -n cosign-system get cm config-sigstore-keys -ojsonpath='{.data.bring-your-own-sigstore-keys}' | yq '.tlogs[0].publicKey.rawBytes' | base64 -d | openssl pkey -pubin -inform der > ./got.rekor.pem diff ./got.rekor.pem ./test/testdata/trustroot/golden/rekor.pem echo "Validating CTLog entry" kubectl -n cosign-system get cm config-sigstore-keys -ojsonpath='{.data.bring-your-own-sigstore-keys}' | yq '.ctlogs[0].publicKey.rawBytes' | base64 -d | openssl pkey -pubin -inform der > ./got.ctfe.pem diff ./got.ctfe.pem ./test/testdata/trustroot/golden/ctfe.pem kubectl delete -f ./test/testdata/trustroot/valid/valid-sigstore-keys.yaml echo '::endgroup::' ================================================ FILE: test/kustomize/kustomization.yaml ================================================ # 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 # # https://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. apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - policy-controller-e2e.yaml patches: - patch: |- - op: add path: /spec/template/spec/containers/0/args/- value: --tuf-mirror=http://tuf.tuf-system.svc - op: add path: /spec/template/spec/containers/0/args/- value: --tuf-root=/var/run/tuf/root.json target: kind: Deployment name: webhook ================================================ FILE: test/kustomize-no-tuf/kustomization.yaml ================================================ # 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 # # https://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. apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization resources: - policy-controller-e2e.yaml # Note we give garbage arguments to tuf-root and tuf-mirror to make it a good # test to verify that these paths are not even executed. patches: - patch: |- - op: add path: /spec/template/spec/containers/0/args/- value: --tuf-mirror=http://sigstore.example.com - op: add path: /spec/template/spec/containers/0/args/- value: --tuf-root=/root-that-is-not-there.json - op: add path: /spec/template/spec/containers/0/args/- value: --disable-tuf=true target: kind: Deployment name: webhook ================================================ FILE: test/testdata/attestations/vuln-predicate.json ================================================ { "invocation": { "parameters": null, "uri": "invocation.example.com/cosign-testing", "event_id": "", "builder.id": "" }, "scanner": { "uri": "fakescanner.example.com/cosign-testing", "version": "", "db": { "uri": "", "version": "" }, "result": null }, "metadata": { "scanStartedOn": "2022-04-12T00:00:00Z", "scanFinishedOn": "2022-04-12T00:10:00Z" } } ================================================ FILE: test/testdata/bom-go-mod.spdx ================================================ SPDXVersion: SPDX-2.2 DataLicense: CC0-1.0 SPDXID: SPDXRef-DOCUMENT DocumentName: github.com/sigstore/cosign DocumentNamespace: http://spdx.org/spdxpackages/github.com/sigstore/cosign-9a615223-fdf6-40cc-8156-666d7da86672 Creator: Tool: spdx-sbom-generator-0.0.1 Created: 2021-06-27T13:42:53Z ##### Package representing the github.com/sigstore/cosign PackageName: github.com/sigstore/cosign SPDXID: SPDXRef-Package-github.com.sigstore.cosign PackageVersion: ddd9132 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 0d8975f6ff7067f2adad485924e0854caec9c5d46306bf5b901d311c2fb05a7a PackageHomePage: https://github.com/sigstore/cosign PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-DOCUMENT DESCRIBES SPDXRef-Package-github.com.sigstore.cosign Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-k8s.io.apimachinery-v0.21.2 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.go-openapi.analysis-v0.20.1 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.go-openapi.strfmt-v0.20.1 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.leodido.go-urn-v1.2.1 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.peterbourgon.ff.v3-v3.0.0 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.cyberphone.json-canonicalization-v0.0.0-20210303052042-6bc126869bf4 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.pelletier.go-toml-v1.9.3 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.spf13.afero-v1.6.0 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.theupdateframework.go-tuf-v0.0.0-20201230183259-aee6270feb55 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-google.golang.org.genproto-v0.0.0-20210617175327-b9e0b3197ced Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.go-openapi.swag-v0.19.15 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.google.gofuzz-v1.2.0 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.pkg.errors-v0.9.1 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.prometheus.common-v0.29.0 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-go.uber.org.multierr-v1.7.0 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-golang.org.x.term-v0.0.0-20210615171337-6886f2dfbf5b Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-k8s.io.api-v0.21.2 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-k8s.io.client-go-v0.21.2 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.google.go-cmp-v0.5.6 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.google.go-containerregistry-v0.5.1 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.jedisct1.go-minisign-v0.0.0-20210414164026-819d7e2534ac Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-go.mongodb.org.mongo-driver-v1.5.3 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-golang.org.x.sync-v0.0.0-20210220032951-036812b2e83c Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.magiconair.properties-v1.8.5 Relationship SPDXRef-Package-github.com.sigstore.cosign DEPENDS_ON SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 ##### Package representing the github.com/google/go-containerregistry PackageName: github.com/google/go-containerregistry SPDXID: SPDXRef-Package-github.com.google.go-containerregistry-v0.5.1 PackageVersion: v0.5.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 9f611b3f2b625e9f4af823b9833dfd4317f575a270cd6c156ee9f5b89ec49454 PackageHomePage: https://github.com/google/go-containerregistry PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.google.go-containerregistry-v0.5.1 DEPENDS_ON SPDXRef-Package-cloud.google.com.go-v0.81.0 Relationship SPDXRef-Package-github.com.google.go-containerregistry-v0.5.1 DEPENDS_ON SPDXRef-Package-github.com.docker.cli-v0.0.0-20191017083524-a8ff7f821017 Relationship SPDXRef-Package-github.com.google.go-containerregistry-v0.5.1 DEPENDS_ON SPDXRef-Package-github.com.opencontainers.image-spec-v1.0.1 Relationship SPDXRef-Package-github.com.google.go-containerregistry-v0.5.1 DEPENDS_ON SPDXRef-Package-github.com.sirupsen.logrus-v1.8.1 Relationship SPDXRef-Package-github.com.google.go-containerregistry-v0.5.1 DEPENDS_ON SPDXRef-Package-golang.org.x.time-v0.0.0-20210220033141-f8bda1e9f3ba Relationship SPDXRef-Package-github.com.google.go-containerregistry-v0.5.1 DEPENDS_ON SPDXRef-Package-k8s.io.klog.v2-v2.8.0 Relationship SPDXRef-Package-github.com.google.go-containerregistry-v0.5.1 DEPENDS_ON SPDXRef-Package-google.golang.org.genproto-v0.0.0-20210617175327-b9e0b3197ced Relationship SPDXRef-Package-github.com.google.go-containerregistry-v0.5.1 DEPENDS_ON SPDXRef-Package-github.com.containerd.stargz-snapshotter.estargz-v0.4.1 Relationship SPDXRef-Package-github.com.google.go-containerregistry-v0.5.1 DEPENDS_ON SPDXRef-Package-github.com.docker.docker-v1.4.2-0.20200319182547-c7ad2b866182 Relationship SPDXRef-Package-github.com.google.go-containerregistry-v0.5.1 DEPENDS_ON SPDXRef-Package-github.com.docker.docker-credential-helpers-v0.6.3 Relationship SPDXRef-Package-github.com.google.go-containerregistry-v0.5.1 DEPENDS_ON SPDXRef-Package-github.com.spf13.cobra-v1.1.3 Relationship SPDXRef-Package-github.com.google.go-containerregistry-v0.5.1 DEPENDS_ON SPDXRef-Package-golang.org.x.sync-v0.0.0-20210220032951-036812b2e83c Relationship SPDXRef-Package-github.com.google.go-containerregistry-v0.5.1 DEPENDS_ON SPDXRef-Package-golang.org.x.text-v0.3.6 Relationship SPDXRef-Package-github.com.google.go-containerregistry-v0.5.1 DEPENDS_ON SPDXRef-Package-github.com.gorilla.mux-v1.8.0 Relationship SPDXRef-Package-github.com.google.go-containerregistry-v0.5.1 DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 Relationship SPDXRef-Package-github.com.google.go-containerregistry-v0.5.1 DEPENDS_ON SPDXRef-Package-github.com.docker.distribution-v2.7.1+incompatible Relationship SPDXRef-Package-github.com.google.go-containerregistry-v0.5.1 DEPENDS_ON SPDXRef-Package-github.com.google.go-cmp-v0.5.6 Relationship SPDXRef-Package-github.com.google.go-containerregistry-v0.5.1 DEPENDS_ON SPDXRef-Package-golang.org.x.oauth2-v0.0.0-20210514164344-f6687ab2804c ##### Package representing the github.com/peterbourgon/ff/v3 PackageName: github.com/peterbourgon/ff/v3 SPDXID: SPDXRef-Package-github.com.peterbourgon.ff.v3-v3.0.0 PackageVersion: v3.0.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 717d2deecd326f89ac03355a0c60e7af8cec09cdf35c739c9db64677b7f767ae PackageHomePage: https://github.com/peterbourgon/ff/v3 PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.peterbourgon.ff.v3-v3.0.0 DEPENDS_ON SPDXRef-Package-github.com.pelletier.go-toml-v1.9.3 Relationship SPDXRef-Package-github.com.peterbourgon.ff.v3-v3.0.0 DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 ##### Package representing the github.com/pkg/errors PackageName: github.com/pkg/errors SPDXID: SPDXRef-Package-github.com.pkg.errors-v0.9.1 PackageVersion: v0.9.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: e984effb1b0eef5e6cfefb3f37f23bfaee28d5180f11c64fb43a46b7f7421edb PackageHomePage: https://github.com/pkg/errors PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/docker/cli PackageName: github.com/docker/cli SPDXID: SPDXRef-Package-github.com.docker.cli-v0.0.0-20191017083524-a8ff7f821017 PackageVersion: v0.0.0-20191017083524-a8ff7f821017 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 0e16595382ffbd6bd8cd20be937e87ad48d5e20d678fb52b4913740565cb5e26 PackageHomePage: https://github.com/docker/cli PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/docker/docker-credential-helpers PackageName: github.com/docker/docker-credential-helpers SPDXID: SPDXRef-Package-github.com.docker.docker-credential-helpers-v0.6.3 PackageVersion: v0.6.3 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 0a83f71929507b20f2c695a3a5833519fcf606d470948b083847e31c09433bee PackageHomePage: https://github.com/docker/docker-credential-helpers PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/docker/docker PackageName: github.com/docker/docker SPDXID: SPDXRef-Package-github.com.docker.docker-v1.4.2-0.20200319182547-c7ad2b866182 PackageVersion: v1.4.2-0.20200319182547-c7ad2b866182 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: b48d221328853f35e846891d066cbfbbfd0f0e8e15d37745d68215d4bfa663c5 PackageHomePage: https://github.com/docker/docker PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/opencontainers/go-digest PackageName: github.com/opencontainers/go-digest SPDXID: SPDXRef-Package-github.com.opencontainers.go-digest-v1.0.0 PackageVersion: v1.0.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 06744ce2bb1c85d4117a2ba9e9a817665e52ed5f36e9722e8fada53867a9fae1 PackageHomePage: https://github.com/opencontainers/go-digest PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/opencontainers/image-spec PackageName: github.com/opencontainers/image-spec SPDXID: SPDXRef-Package-github.com.opencontainers.image-spec-v1.0.1 PackageVersion: v1.0.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: e3790a1082e695077024de83b32cfc198508585d3e37d430aaa325cfbe0c4a0f PackageHomePage: https://github.com/opencontainers/image-spec PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/docker/distribution PackageName: github.com/docker/distribution SPDXID: SPDXRef-Package-github.com.docker.distribution-v2.7.1+incompatible PackageVersion: v2.7.1+incompatible PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 1e591e4b18738469da7205179340f527fe732e0c3cba080abd084828a3a16d7f PackageHomePage: https://github.com/docker/distribution PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the golang.org/x/sync PackageName: golang.org/x/sync SPDXID: SPDXRef-Package-golang.org.x.sync-v0.0.0-20210220032951-036812b2e83c PackageVersion: v0.0.0-20210220032951-036812b2e83c PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: c2c8d8b8e332215da159aa126456187286e44d97353e0566e77e350e5a8522f7 PackageHomePage: https://golang.org/x/sync PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/cyberphone/json-canonicalization PackageName: github.com/cyberphone/json-canonicalization SPDXID: SPDXRef-Package-github.com.cyberphone.json-canonicalization-v0.0.0-20210303052042-6bc126869bf4 PackageVersion: v0.0.0-20210303052042-6bc126869bf4 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: c7ebd3e43ca55f29f282acbf5e9194741d64f027cf57cc6d8136c0e6a30451a6 PackageHomePage: https://github.com/cyberphone/json-canonicalization PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/asaskevich/govalidator PackageName: github.com/asaskevich/govalidator SPDXID: SPDXRef-Package-github.com.asaskevich.govalidator-v0.0.0-20210307081110-f21760c49a8d PackageVersion: v0.0.0-20210307081110-f21760c49a8d PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 903cd7f5e7c6ac40eb2de2d6dfe3be0622f9bce5ad6c422fad4966939fcabf94 PackageHomePage: https://github.com/asaskevich/govalidator PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/go-openapi/errors PackageName: github.com/go-openapi/errors SPDXID: SPDXRef-Package-github.com.go-openapi.errors-v0.20.0 PackageVersion: v0.20.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 51ad642cf65adce9300b5ea390808246e8feeed0bcd81fbbb88e1b070a1238d2 PackageHomePage: https://github.com/go-openapi/errors PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.go-openapi.errors-v0.20.0 DEPENDS_ON SPDXRef-Package-github.com.davecgh.go-spew-v1.1.1 ##### Package representing the github.com/mitchellh/mapstructure PackageName: github.com/mitchellh/mapstructure SPDXID: SPDXRef-Package-github.com.mitchellh.mapstructure-v1.4.1 PackageVersion: v1.4.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 3b17e495d6eceeb7e78bedaca087bcfc81f454c9a8dbce3ccec9071a0ecea479 PackageHomePage: https://github.com/mitchellh/mapstructure PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/oklog/ulid PackageName: github.com/oklog/ulid SPDXID: SPDXRef-Package-github.com.oklog.ulid-v1.3.1 PackageVersion: v1.3.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: d906eb8403330115effa40cdde3173f4187286eea72acd78a7f0383c437b875d PackageHomePage: https://github.com/oklog/ulid PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the go.mongodb.org/mongo-driver PackageName: go.mongodb.org/mongo-driver SPDXID: SPDXRef-Package-go.mongodb.org.mongo-driver-v1.5.3 PackageVersion: v1.5.3 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: a4ccad268cfd8a059f9b68ccd6f1ca5ae83cdab8c974dad74d75e53b9748fcb9 PackageHomePage: https://go.mongodb.org/mongo-driver PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-go.mongodb.org.mongo-driver-v1.5.3 DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 Relationship SPDXRef-Package-go.mongodb.org.mongo-driver-v1.5.3 DEPENDS_ON SPDXRef-Package-github.com.go-stack.stack-v1.8.0 Relationship SPDXRef-Package-go.mongodb.org.mongo-driver-v1.5.3 DEPENDS_ON SPDXRef-Package-github.com.golang.snappy-v0.0.3 Relationship SPDXRef-Package-go.mongodb.org.mongo-driver-v1.5.3 DEPENDS_ON SPDXRef-Package-github.com.google.go-cmp-v0.5.6 Relationship SPDXRef-Package-go.mongodb.org.mongo-driver-v1.5.3 DEPENDS_ON SPDXRef-Package-github.com.pkg.errors-v0.9.1 Relationship SPDXRef-Package-go.mongodb.org.mongo-driver-v1.5.3 DEPENDS_ON SPDXRef-Package-github.com.sirupsen.logrus-v1.8.1 Relationship SPDXRef-Package-go.mongodb.org.mongo-driver-v1.5.3 DEPENDS_ON SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e Relationship SPDXRef-Package-go.mongodb.org.mongo-driver-v1.5.3 DEPENDS_ON SPDXRef-Package-golang.org.x.sync-v0.0.0-20210220032951-036812b2e83c Relationship SPDXRef-Package-go.mongodb.org.mongo-driver-v1.5.3 DEPENDS_ON SPDXRef-Package-github.com.pelletier.go-toml-v1.9.3 Relationship SPDXRef-Package-go.mongodb.org.mongo-driver-v1.5.3 DEPENDS_ON SPDXRef-Package-golang.org.x.text-v0.3.6 ##### Package representing the github.com/go-stack/stack PackageName: github.com/go-stack/stack SPDXID: SPDXRef-Package-github.com.go-stack.stack-v1.8.0 PackageVersion: v1.8.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: fd3f25fb63423cea94320198b7efaa88ed8e38cd2862f1be66b644e263c751d9 PackageHomePage: https://github.com/go-stack/stack PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/go-openapi/strfmt PackageName: github.com/go-openapi/strfmt SPDXID: SPDXRef-Package-github.com.go-openapi.strfmt-v0.20.1 PackageVersion: v0.20.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 60fb8854b5971069860ab2102510a7eb28790a49eb2fb9d1aeb98a3f34833525 PackageHomePage: https://github.com/go-openapi/strfmt PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.go-openapi.strfmt-v0.20.1 DEPENDS_ON SPDXRef-Package-github.com.mitchellh.mapstructure-v1.4.1 Relationship SPDXRef-Package-github.com.go-openapi.strfmt-v0.20.1 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.errors-v0.20.0 Relationship SPDXRef-Package-github.com.go-openapi.strfmt-v0.20.1 DEPENDS_ON SPDXRef-Package-github.com.davecgh.go-spew-v1.1.1 Relationship SPDXRef-Package-github.com.go-openapi.strfmt-v0.20.1 DEPENDS_ON SPDXRef-Package-github.com.asaskevich.govalidator-v0.0.0-20210307081110-f21760c49a8d Relationship SPDXRef-Package-github.com.go-openapi.strfmt-v0.20.1 DEPENDS_ON SPDXRef-Package-go.mongodb.org.mongo-driver-v1.5.3 Relationship SPDXRef-Package-github.com.go-openapi.strfmt-v0.20.1 DEPENDS_ON SPDXRef-Package-github.com.oklog.ulid-v1.3.1 Relationship SPDXRef-Package-github.com.go-openapi.strfmt-v0.20.1 DEPENDS_ON SPDXRef-Package-github.com.mailru.easyjson-v0.7.7 Relationship SPDXRef-Package-github.com.go-openapi.strfmt-v0.20.1 DEPENDS_ON SPDXRef-Package-github.com.go-stack.stack-v1.8.0 Relationship SPDXRef-Package-github.com.go-openapi.strfmt-v0.20.1 DEPENDS_ON SPDXRef-Package-github.com.google.go-cmp-v0.5.6 ##### Package representing the github.com/josharian/intern PackageName: github.com/josharian/intern SPDXID: SPDXRef-Package-github.com.josharian.intern-v1.0.0 PackageVersion: v1.0.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 02952b87b56340b825e2381df45a0b5eff5dd1bf290fdfada7dbe6e993a42076 PackageHomePage: https://github.com/josharian/intern PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/mailru/easyjson PackageName: github.com/mailru/easyjson SPDXID: SPDXRef-Package-github.com.mailru.easyjson-v0.7.7 PackageVersion: v0.7.7 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 827a48dc29ec1ff4c2b1ec78221db470416ed364dac6a878893e9d21cefa6918 PackageHomePage: https://github.com/mailru/easyjson PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.mailru.easyjson-v0.7.7 DEPENDS_ON SPDXRef-Package-github.com.josharian.intern-v1.0.0 ##### Package representing the gopkg.in/yaml.v2 PackageName: gopkg.in/yaml.v2 SPDXID: SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 PackageVersion: v2.4.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 3aed1e3fc7b0a044fb38213f8c11cb20d5b45fd673e45de14c537648c446e6be PackageHomePage: https://gopkg.in/yaml.v2 PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/go-openapi/swag PackageName: github.com/go-openapi/swag SPDXID: SPDXRef-Package-github.com.go-openapi.swag-v0.19.15 PackageVersion: v0.19.15 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: e725f85ebbbcc1e303a950fe6dfb589e4a6003989316fda6ac5514b818bc0830 PackageHomePage: https://github.com/go-openapi/swag PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.go-openapi.swag-v0.19.15 DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 Relationship SPDXRef-Package-github.com.go-openapi.swag-v0.19.15 DEPENDS_ON SPDXRef-Package-github.com.mailru.easyjson-v0.7.7 Relationship SPDXRef-Package-github.com.go-openapi.swag-v0.19.15 DEPENDS_ON SPDXRef-Package-github.com.davecgh.go-spew-v1.1.1 ##### Package representing the github.com/google/trillian PackageName: github.com/google/trillian SPDXID: SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f PackageVersion: v1.3.14-0.20210413093047-5e12fb368c8f PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 4dab9fd4947a0cb0710d75145cf7eeb32462b10c5a422170dff8aa54f0b64ae3 PackageHomePage: https://github.com/google/trillian PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-github.com.olekukonko.tablewriter-v0.0.5 Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-github.com.prometheus.client-model-v0.2.0 Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-google.golang.org.grpc-v1.38.0 Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-go.uber.org.zap-v1.16.0 Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-github.com.google.certificate-transparency-go-v1.1.1 Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-github.com.mattn.go-runewidth-v0.0.9 Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-github.com.spf13.cobra-v1.1.3 Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-go.opencensus.io-v0.23.0 Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-go.uber.org.multierr-v1.7.0 Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-golang.org.x.sync-v0.0.0-20210220032951-036812b2e83c Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-golang.org.x.time-v0.0.0-20210220033141-f8bda1e9f3ba Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-google.golang.org.genproto-v0.0.0-20210617175327-b9e0b3197ced Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-github.com.golang.protobuf-v1.5.2 Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-github.com.google.go-cmp-v0.5.6 Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-github.com.gogo.protobuf-v1.3.2 Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-github.com.spf13.pflag-v1.0.5 Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-google.golang.org.protobuf-v1.26.0 Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-github.com.imdario.mergo-v0.3.9 Relationship SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f DEPENDS_ON SPDXRef-Package-google.golang.org.api-v0.46.0 ##### Package representing the github.com/containerd/stargz-snapshotter/estargz PackageName: github.com/containerd/stargz-snapshotter/estargz SPDXID: SPDXRef-Package-github.com.containerd.stargz-snapshotter.estargz-v0.4.1 PackageVersion: v0.4.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 7c5efb46f869997b7bd0902b05024d6b3d8575e9d42a5ea11e37855aa8a8f8ae PackageHomePage: https://github.com/containerd/stargz-snapshotter/estargz PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.containerd.stargz-snapshotter.estargz-v0.4.1 DEPENDS_ON SPDXRef-Package-github.com.opencontainers.go-digest-v1.0.0 Relationship SPDXRef-Package-github.com.containerd.stargz-snapshotter.estargz-v0.4.1 DEPENDS_ON SPDXRef-Package-golang.org.x.sync-v0.0.0-20210220032951-036812b2e83c Relationship SPDXRef-Package-github.com.containerd.stargz-snapshotter.estargz-v0.4.1 DEPENDS_ON SPDXRef-Package-github.com.pkg.errors-v0.9.1 ##### Package representing the github.com/sigstore/sigstore PackageName: github.com/sigstore/sigstore SPDXID: SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 PackageVersion: v0.0.0-20210609084117-386ea718fc64 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: ce32f696897cc9eea099740ba18e1f2e345516f1c1a8ddf294c2662a7fca2c68 PackageHomePage: https://github.com/sigstore/sigstore PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.swag-v0.19.15 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.google.go-containerregistry-v0.5.1 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-golang.org.x.time-v0.0.0-20210220033141-f8bda1e9f3ba Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.asaskevich.govalidator-v0.0.0-20210307081110-f21760c49a8d Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.pkg.errors-v0.9.1 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-google.golang.org.protobuf-v1.26.0 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.strfmt-v0.20.1 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.spf13.cobra-v1.1.3 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.pierrec.lz4-v2.6.0+incompatible Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.vault.api-v1.1.0 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.errwrap-v1.1.0 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.errors-v0.20.0 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.golang.protobuf-v1.5.2 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-gopkg.in.square.go-jose.v2-v2.5.1 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.go-multierror-v1.1.1 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.go-cleanhttp-v0.5.2 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.segmentio.ksuid-v1.0.3 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-cloud.google.com.go-v0.81.0 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.coreos.go-oidc.v3-v3.0.0 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.validate-v0.20.2 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-golang.org.x.oauth2-v0.0.0-20210514164344-f6687ab2804c Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.mitchellh.go-homedir-v1.1.0 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.skratchdot.open-golang-v0.0.0-20200116055534-eef842397966 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.spf13.viper-v1.7.1 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-google.golang.org.genproto-v0.0.0-20210617175327-b9e0b3197ced Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.go-retryablehttp-v0.6.8 Relationship SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 DEPENDS_ON SPDXRef-Package-github.com.golang.snappy-v0.0.3 ##### Package representing the github.com/go-openapi/runtime PackageName: github.com/go-openapi/runtime SPDXID: SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 PackageVersion: v0.19.29 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 06262c89eea66a0d240bb2e2dcf20608e29cee7d946804545266e2e195f0399c PackageHomePage: https://github.com/go-openapi/runtime PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.swag-v0.19.15 Relationship SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.validate-v0.20.2 Relationship SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 DEPENDS_ON SPDXRef-Package-github.com.opentracing.opentracing-go-v1.2.0 Relationship SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 Relationship SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 DEPENDS_ON SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e Relationship SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 DEPENDS_ON SPDXRef-Package-go.mongodb.org.mongo-driver-v1.5.3 Relationship SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.analysis-v0.20.1 Relationship SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.strfmt-v0.20.1 Relationship SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 Relationship SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 DEPENDS_ON SPDXRef-Package-github.com.PuerkitoBio.purell-v1.1.1 Relationship SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.jsonpointer-v0.19.5 Relationship SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 Relationship SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 DEPENDS_ON SPDXRef-Package-github.com.asaskevich.govalidator-v0.0.0-20210307081110-f21760c49a8d Relationship SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.spec-v0.20.3 Relationship SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.jsonreference-v0.19.5 Relationship SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 DEPENDS_ON SPDXRef-Package-github.com.mailru.easyjson-v0.7.7 Relationship SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.errors-v0.20.0 Relationship SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 DEPENDS_ON SPDXRef-Package-github.com.mitchellh.mapstructure-v1.4.1 ##### Package representing the github.com/go-openapi/analysis PackageName: github.com/go-openapi/analysis SPDXID: SPDXRef-Package-github.com.go-openapi.analysis-v0.20.1 PackageVersion: v0.20.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 44e10c5f201ef8dd4a7700d7a8729665fe0b8e22a506c381cda0f1b95d2cbf7f PackageHomePage: https://github.com/go-openapi/analysis PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.go-openapi.analysis-v0.20.1 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.strfmt-v0.20.1 Relationship SPDXRef-Package-github.com.go-openapi.analysis-v0.20.1 DEPENDS_ON SPDXRef-Package-github.com.mitchellh.mapstructure-v1.4.1 Relationship SPDXRef-Package-github.com.go-openapi.analysis-v0.20.1 DEPENDS_ON SPDXRef-Package-go.mongodb.org.mongo-driver-v1.5.3 Relationship SPDXRef-Package-github.com.go-openapi.analysis-v0.20.1 DEPENDS_ON SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e Relationship SPDXRef-Package-github.com.go-openapi.analysis-v0.20.1 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 Relationship SPDXRef-Package-github.com.go-openapi.analysis-v0.20.1 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-github.com.go-openapi.analysis-v0.20.1 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.jsonreference-v0.19.5 Relationship SPDXRef-Package-github.com.go-openapi.analysis-v0.20.1 DEPENDS_ON SPDXRef-Package-github.com.asaskevich.govalidator-v0.0.0-20210307081110-f21760c49a8d Relationship SPDXRef-Package-github.com.go-openapi.analysis-v0.20.1 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.errors-v0.20.0 Relationship SPDXRef-Package-github.com.go-openapi.analysis-v0.20.1 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.jsonpointer-v0.19.5 Relationship SPDXRef-Package-github.com.go-openapi.analysis-v0.20.1 DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 Relationship SPDXRef-Package-github.com.go-openapi.analysis-v0.20.1 DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 Relationship SPDXRef-Package-github.com.go-openapi.analysis-v0.20.1 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.spec-v0.20.3 Relationship SPDXRef-Package-github.com.go-openapi.analysis-v0.20.1 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.swag-v0.19.15 Relationship SPDXRef-Package-github.com.go-openapi.analysis-v0.20.1 DEPENDS_ON SPDXRef-Package-github.com.mailru.easyjson-v0.7.7 ##### Package representing the github.com/go-openapi/jsonpointer PackageName: github.com/go-openapi/jsonpointer SPDXID: SPDXRef-Package-github.com.go-openapi.jsonpointer-v0.19.5 PackageVersion: v0.19.5 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 1d3f0415980a62cec07254fc3e99ff4aebaa1f510b37968d6c44f7755520f3f0 PackageHomePage: https://github.com/go-openapi/jsonpointer PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.go-openapi.jsonpointer-v0.19.5 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.swag-v0.19.15 Relationship SPDXRef-Package-github.com.go-openapi.jsonpointer-v0.19.5 DEPENDS_ON SPDXRef-Package-github.com.mailru.easyjson-v0.7.7 Relationship SPDXRef-Package-github.com.go-openapi.jsonpointer-v0.19.5 DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 Relationship SPDXRef-Package-github.com.go-openapi.jsonpointer-v0.19.5 DEPENDS_ON SPDXRef-Package-github.com.davecgh.go-spew-v1.1.1 ##### Package representing the github.com/PuerkitoBio/urlesc PackageName: github.com/PuerkitoBio/urlesc SPDXID: SPDXRef-Package-github.com.PuerkitoBio.urlesc-v0.0.0-20170810143723-de5bf2ad4578 PackageVersion: v0.0.0-20170810143723-de5bf2ad4578 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: cf5a45a083cd213c91fb7d67e61188f8eaa1d362903b9ec91d8cf8d2494a050e PackageHomePage: https://github.com/PuerkitoBio/urlesc PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the golang.org/x/text PackageName: golang.org/x/text SPDXID: SPDXRef-Package-golang.org.x.text-v0.3.6 PackageVersion: v0.3.6 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: d880df5dea6c92d960d64f6fe6c27d88f226838eccbf4736497a5c9f1f7072fd PackageHomePage: https://golang.org/x/text PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the golang.org/x/net PackageName: golang.org/x/net SPDXID: SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 PackageVersion: v0.0.0-20210525063256-abc453219eb5 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 7796fea5e6483954436c0df99da0a78100ee5157c3b2e8fd99dcdaf157e7e398 PackageHomePage: https://golang.org/x/net PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 Relationship SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 DEPENDS_ON SPDXRef-Package-golang.org.x.term-v0.0.0-20210615171337-6886f2dfbf5b Relationship SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 DEPENDS_ON SPDXRef-Package-golang.org.x.text-v0.3.6 Relationship SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 DEPENDS_ON SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e ##### Package representing the github.com/PuerkitoBio/purell PackageName: github.com/PuerkitoBio/purell SPDXID: SPDXRef-Package-github.com.PuerkitoBio.purell-v1.1.1 PackageVersion: v1.1.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 8c01b4b8b4e77bd82080a9a2072c7a9b8539d43b88cd419ee9dc3a04d4b905e0 PackageHomePage: https://github.com/PuerkitoBio/purell PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/go-openapi/jsonreference PackageName: github.com/go-openapi/jsonreference SPDXID: SPDXRef-Package-github.com.go-openapi.jsonreference-v0.19.5 PackageVersion: v0.19.5 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: c9b645f4b15ac8886ae3f1f2ce467af096ecc6b74d0c89cfcb044ec90a05161a PackageHomePage: https://github.com/go-openapi/jsonreference PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.go-openapi.jsonreference-v0.19.5 DEPENDS_ON SPDXRef-Package-github.com.PuerkitoBio.urlesc-v0.0.0-20170810143723-de5bf2ad4578 Relationship SPDXRef-Package-github.com.go-openapi.jsonreference-v0.19.5 DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 Relationship SPDXRef-Package-github.com.go-openapi.jsonreference-v0.19.5 DEPENDS_ON SPDXRef-Package-github.com.mailru.easyjson-v0.7.7 Relationship SPDXRef-Package-github.com.go-openapi.jsonreference-v0.19.5 DEPENDS_ON SPDXRef-Package-github.com.davecgh.go-spew-v1.1.1 Relationship SPDXRef-Package-github.com.go-openapi.jsonreference-v0.19.5 DEPENDS_ON SPDXRef-Package-github.com.PuerkitoBio.purell-v1.1.1 Relationship SPDXRef-Package-github.com.go-openapi.jsonreference-v0.19.5 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-github.com.go-openapi.jsonreference-v0.19.5 DEPENDS_ON SPDXRef-Package-golang.org.x.text-v0.3.6 Relationship SPDXRef-Package-github.com.go-openapi.jsonreference-v0.19.5 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.swag-v0.19.15 Relationship SPDXRef-Package-github.com.go-openapi.jsonreference-v0.19.5 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.jsonpointer-v0.19.5 ##### Package representing the github.com/go-openapi/spec PackageName: github.com/go-openapi/spec SPDXID: SPDXRef-Package-github.com.go-openapi.spec-v0.20.3 PackageVersion: v0.20.3 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: de8a34d1f7e6459c9343a159264930fcc394d1cf38d33505638e5713306cf684 PackageHomePage: https://github.com/go-openapi/spec PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.go-openapi.spec-v0.20.3 DEPENDS_ON SPDXRef-Package-golang.org.x.text-v0.3.6 Relationship SPDXRef-Package-github.com.go-openapi.spec-v0.20.3 DEPENDS_ON SPDXRef-Package-github.com.mailru.easyjson-v0.7.7 Relationship SPDXRef-Package-github.com.go-openapi.spec-v0.20.3 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.swag-v0.19.15 Relationship SPDXRef-Package-github.com.go-openapi.spec-v0.20.3 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.jsonreference-v0.19.5 Relationship SPDXRef-Package-github.com.go-openapi.spec-v0.20.3 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.jsonpointer-v0.19.5 Relationship SPDXRef-Package-github.com.go-openapi.spec-v0.20.3 DEPENDS_ON SPDXRef-Package-github.com.davecgh.go-spew-v1.1.1 Relationship SPDXRef-Package-github.com.go-openapi.spec-v0.20.3 DEPENDS_ON SPDXRef-Package-github.com.PuerkitoBio.purell-v1.1.1 Relationship SPDXRef-Package-github.com.go-openapi.spec-v0.20.3 DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 Relationship SPDXRef-Package-github.com.go-openapi.spec-v0.20.3 DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 Relationship SPDXRef-Package-github.com.go-openapi.spec-v0.20.3 DEPENDS_ON SPDXRef-Package-github.com.PuerkitoBio.urlesc-v0.0.0-20170810143723-de5bf2ad4578 Relationship SPDXRef-Package-github.com.go-openapi.spec-v0.20.3 DEPENDS_ON SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e Relationship SPDXRef-Package-github.com.go-openapi.spec-v0.20.3 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 ##### Package representing the github.com/go-openapi/loads PackageName: github.com/go-openapi/loads SPDXID: SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 PackageVersion: v0.20.2 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 93af64986aaf16f34f4a9fb02445573eda636219ecf4e5c03eece7d4b05a1231 PackageHomePage: https://github.com/go-openapi/loads PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.jsonreference-v0.19.5 Relationship SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.strfmt-v0.20.1 Relationship SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 DEPENDS_ON SPDXRef-Package-golang.org.x.text-v0.3.6 Relationship SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.validate-v0.20.2 Relationship SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.asaskevich.govalidator-v0.0.0-20210307081110-f21760c49a8d Relationship SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.davecgh.go-spew-v1.1.1 Relationship SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.errors-v0.20.0 Relationship SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.jsonpointer-v0.19.5 Relationship SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.spec-v0.20.3 Relationship SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.swag-v0.19.15 Relationship SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.mitchellh.mapstructure-v1.4.1 Relationship SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 Relationship SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.PuerkitoBio.purell-v1.1.1 Relationship SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 DEPENDS_ON SPDXRef-Package-go.mongodb.org.mongo-driver-v1.5.3 Relationship SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.analysis-v0.20.1 Relationship SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.mailru.easyjson-v0.7.7 Relationship SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.PuerkitoBio.urlesc-v0.0.0-20170810143723-de5bf2ad4578 ##### Package representing the github.com/go-openapi/validate PackageName: github.com/go-openapi/validate SPDXID: SPDXRef-Package-github.com.go-openapi.validate-v0.20.2 PackageVersion: v0.20.2 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 57a89cb5a4af0a5df24c668749126006f2c0beb29e77d6915cdf54f07f1671b4 PackageHomePage: https://github.com/go-openapi/validate PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.go-openapi.validate-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.asaskevich.govalidator-v0.0.0-20210307081110-f21760c49a8d Relationship SPDXRef-Package-github.com.go-openapi.validate-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 Relationship SPDXRef-Package-github.com.go-openapi.validate-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.strfmt-v0.20.1 Relationship SPDXRef-Package-github.com.go-openapi.validate-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.swag-v0.19.15 Relationship SPDXRef-Package-github.com.go-openapi.validate-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.mitchellh.mapstructure-v1.4.1 Relationship SPDXRef-Package-github.com.go-openapi.validate-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.spec-v0.20.3 Relationship SPDXRef-Package-github.com.go-openapi.validate-v0.20.2 DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 Relationship SPDXRef-Package-github.com.go-openapi.validate-v0.20.2 DEPENDS_ON SPDXRef-Package-go.mongodb.org.mongo-driver-v1.5.3 Relationship SPDXRef-Package-github.com.go-openapi.validate-v0.20.2 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-github.com.go-openapi.validate-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.analysis-v0.20.1 Relationship SPDXRef-Package-github.com.go-openapi.validate-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.errors-v0.20.0 Relationship SPDXRef-Package-github.com.go-openapi.validate-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.jsonpointer-v0.19.5 Relationship SPDXRef-Package-github.com.go-openapi.validate-v0.20.2 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 ##### Package representing the github.com/opentracing/opentracing-go PackageName: github.com/opentracing/opentracing-go SPDXID: SPDXRef-Package-github.com.opentracing.opentracing-go-v1.2.0 PackageVersion: v1.2.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: dceb5ae504b6c9ad9d36469642fa86f586698d17cc5fd156f9019c688a6b246d PackageHomePage: https://github.com/opentracing/opentracing-go PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/go-playground/locales PackageName: github.com/go-playground/locales SPDXID: SPDXRef-Package-github.com.go-playground.locales-v0.13.0 PackageVersion: v0.13.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 5d0fbcd46768d469dcb9c098b5332a765f0ba65aeb4d46837f3a58aadf2d5f7c PackageHomePage: https://github.com/go-playground/locales PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.go-playground.locales-v0.13.0 DEPENDS_ON SPDXRef-Package-golang.org.x.text-v0.3.6 ##### Package representing the github.com/go-playground/universal-translator PackageName: github.com/go-playground/universal-translator SPDXID: SPDXRef-Package-github.com.go-playground.universal-translator-v0.17.0 PackageVersion: v0.17.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: e4729059a54c41612abd564f297f8b81c23a652da796a100243904de0621e292 PackageHomePage: https://github.com/go-playground/universal-translator PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.go-playground.universal-translator-v0.17.0 DEPENDS_ON SPDXRef-Package-github.com.go-playground.locales-v0.13.0 ##### Package representing the github.com/leodido/go-urn PackageName: github.com/leodido/go-urn SPDXID: SPDXRef-Package-github.com.leodido.go-urn-v1.2.1 PackageVersion: v1.2.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 9ddea28cd322b11a0794bdbc9ef7c08e2e0a5756536c1e16dacfa5a2dacc1ed4 PackageHomePage: https://github.com/leodido/go-urn PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/go-playground/validator PackageName: github.com/go-playground/validator SPDXID: SPDXRef-Package-github.com.go-playground.validator-v9.31.0+incompatible PackageVersion: v9.31.0+incompatible PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: f408f3474f4e7fc4db8a260b696a4907cd03fecf1e216aca2304230e1514392d PackageHomePage: https://github.com/go-playground/validator PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/mitchellh/go-homedir PackageName: github.com/mitchellh/go-homedir SPDXID: SPDXRef-Package-github.com.mitchellh.go-homedir-v1.1.0 PackageVersion: v1.1.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 756f9483a6678379c27563b85c209466b5b22c2006c88ece4ac5eb122edf05e7 PackageHomePage: https://github.com/mitchellh/go-homedir PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/spf13/pflag PackageName: github.com/spf13/pflag SPDXID: SPDXRef-Package-github.com.spf13.pflag-v1.0.5 PackageVersion: v1.0.5 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 1da4c58c01b8de4af39bf5292cf75da8788105be7316cf33bfb9083bd7cc0f68 PackageHomePage: https://github.com/spf13/pflag PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/spf13/cobra PackageName: github.com/spf13/cobra SPDXID: SPDXRef-Package-github.com.spf13.cobra-v1.1.3 PackageVersion: v1.1.3 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 13dae614a8a2f787f92a9e954ca6e630257bb651bd16bb47db56cd9307682759 PackageHomePage: https://github.com/spf13/cobra PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.spf13.cobra-v1.1.3 DEPENDS_ON SPDXRef-Package-github.com.mitchellh.go-homedir-v1.1.0 Relationship SPDXRef-Package-github.com.spf13.cobra-v1.1.3 DEPENDS_ON SPDXRef-Package-github.com.spf13.pflag-v1.0.5 Relationship SPDXRef-Package-github.com.spf13.cobra-v1.1.3 DEPENDS_ON SPDXRef-Package-github.com.spf13.viper-v1.7.1 Relationship SPDXRef-Package-github.com.spf13.cobra-v1.1.3 DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 ##### Package representing the golang.org/x/sys PackageName: golang.org/x/sys SPDXID: SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 PackageVersion: v0.0.0-20210615035016-665e8c7367d1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 094383cb925a141474b7d2dcff3d41acda43f0054ad69c3edf280dd185ddb14d PackageHomePage: https://golang.org/x/sys PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/fsnotify/fsnotify PackageName: github.com/fsnotify/fsnotify SPDXID: SPDXRef-Package-github.com.fsnotify.fsnotify-v1.4.9 PackageVersion: v1.4.9 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 5f5fc2b994c0deb384de9002d35c224d469876760f4380d19fda6831c69ee708 PackageHomePage: https://github.com/fsnotify/fsnotify PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.fsnotify.fsnotify-v1.4.9 DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 ##### Package representing the github.com/hashicorp/hcl PackageName: github.com/hashicorp/hcl SPDXID: SPDXRef-Package-github.com.hashicorp.hcl-v1.0.0 PackageVersion: v1.0.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 895bcea8d965251000f22fadd48cfafbe9540fd5d1bb53a412df05f4eb9ee209 PackageHomePage: https://github.com/hashicorp/hcl PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.hashicorp.hcl-v1.0.0 DEPENDS_ON SPDXRef-Package-github.com.davecgh.go-spew-v1.1.1 ##### Package representing the github.com/magiconair/properties PackageName: github.com/magiconair/properties SPDXID: SPDXRef-Package-github.com.magiconair.properties-v1.8.5 PackageVersion: v1.8.5 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 8279b773031b12daaff1682a11727d765b41ea7f8ba07d82f41c2151dabf50cf PackageHomePage: https://github.com/magiconair/properties PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/pelletier/go-toml PackageName: github.com/pelletier/go-toml SPDXID: SPDXRef-Package-github.com.pelletier.go-toml-v1.9.3 PackageVersion: v1.9.3 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: f21c71d15e543d7bf5ab0de02b01d438920f9cf8c82f6e0eea6ebf4e2f71dfca PackageHomePage: https://github.com/pelletier/go-toml PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.pelletier.go-toml-v1.9.3 DEPENDS_ON SPDXRef-Package-github.com.davecgh.go-spew-v1.1.1 Relationship SPDXRef-Package-github.com.pelletier.go-toml-v1.9.3 DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 ##### Package representing the github.com/spf13/afero PackageName: github.com/spf13/afero SPDXID: SPDXRef-Package-github.com.spf13.afero-v1.6.0 PackageVersion: v1.6.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 0ad525eccf932adf4198a0f145cf92b2ee2dde1f372115a082060411ebc02567 PackageHomePage: https://github.com/spf13/afero PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.spf13.afero-v1.6.0 DEPENDS_ON SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e Relationship SPDXRef-Package-github.com.spf13.afero-v1.6.0 DEPENDS_ON SPDXRef-Package-golang.org.x.text-v0.3.6 ##### Package representing the github.com/spf13/cast PackageName: github.com/spf13/cast SPDXID: SPDXRef-Package-github.com.spf13.cast-v1.3.1 PackageVersion: v1.3.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 62b31a6b804bd52025bc90c20ebfb9330cc7d6d763fbdc4275daf18351526921 PackageHomePage: https://github.com/spf13/cast PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.spf13.cast-v1.3.1 DEPENDS_ON SPDXRef-Package-github.com.davecgh.go-spew-v1.1.1 ##### Package representing the github.com/spf13/jwalterweatherman PackageName: github.com/spf13/jwalterweatherman SPDXID: SPDXRef-Package-github.com.spf13.jwalterweatherman-v1.1.0 PackageVersion: v1.1.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 3a1bde328c7d9a65571ab45c07aedcc3a5ef9259fba27695e8b9b1e74332fd2b PackageHomePage: https://github.com/spf13/jwalterweatherman PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.spf13.jwalterweatherman-v1.1.0 DEPENDS_ON SPDXRef-Package-github.com.davecgh.go-spew-v1.1.1 ##### Package representing the github.com/subosito/gotenv PackageName: github.com/subosito/gotenv SPDXID: SPDXRef-Package-github.com.subosito.gotenv-v1.2.0 PackageVersion: v1.2.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 100a4810859d117550e36abab7faacf5469ec9a5063af11c2eaf515e4788250f PackageHomePage: https://github.com/subosito/gotenv PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the gopkg.in/ini.v1 PackageName: gopkg.in/ini.v1 SPDXID: SPDXRef-Package-gopkg.in.ini.v1-v1.62.0 PackageVersion: v1.62.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: cc6da295ac6329f0763b4d19e87016b801b044bf966e77dbe27bea5b7923d6d7 PackageHomePage: https://gopkg.in/ini.v1 PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/spf13/viper PackageName: github.com/spf13/viper SPDXID: SPDXRef-Package-github.com.spf13.viper-v1.7.1 PackageVersion: v1.7.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 46ff1c376bdd16a5b299764c028eceeb618852e1e0b08e50d000e54e12000410 PackageHomePage: https://github.com/spf13/viper PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-golang.org.x.text-v0.3.6 Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-github.com.golang.groupcache-v0.0.0-20210331224755-41bb18bfe9da Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-github.com.spf13.cast-v1.3.1 Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-github.com.subosito.gotenv-v1.2.0 Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-go.uber.org.atomic-v1.7.0 Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-github.com.spf13.jwalterweatherman-v1.1.0 Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-golang.org.x.time-v0.0.0-20210220033141-f8bda1e9f3ba Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-github.com.fsnotify.fsnotify-v1.4.9 Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-github.com.gogo.protobuf-v1.3.2 Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-github.com.spf13.afero-v1.6.0 Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-github.com.magiconair.properties-v1.8.5 Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-gopkg.in.ini.v1-v1.62.0 Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-google.golang.org.grpc-v1.38.0 Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-go.uber.org.multierr-v1.7.0 Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-go.uber.org.zap-v1.16.0 Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.hcl-v1.0.0 Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-github.com.mitchellh.mapstructure-v1.4.1 Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-github.com.pelletier.go-toml-v1.9.3 Relationship SPDXRef-Package-github.com.spf13.viper-v1.7.1 DEPENDS_ON SPDXRef-Package-github.com.spf13.pflag-v1.0.5 ##### Package representing the github.com/sigstore/rekor PackageName: github.com/sigstore/rekor SPDXID: SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 PackageVersion: v0.1.2-0.20210519014330-b5480728bde6 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 80f722ace48bbeb352bdf56fc02058f966d5cf924243194631b322f93a0208df PackageHomePage: https://github.com/sigstore/rekor PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.blang.semver-v3.5.1+incompatible Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.cavaliercoder.go-rpm-v0.0.0-20200122174316-8cb9fd9c31a8 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.howeyc.gopass-v0.0.0-20190910152052-7cb4b85ec19c Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.spf13.afero-v1.6.0 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.spf13.cast-v1.3.1 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.go-chi.chi-v4.1.2+incompatible Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.mitchellh.mapstructure-v1.4.1 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.mailru.easyjson-v0.7.7 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-google.golang.org.protobuf-v1.26.0 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.google.certificate-transparency-go-v1.1.1 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.ghodss.yaml-v1.0.0 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.spec-v0.20.3 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.strfmt-v0.20.1 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.go-playground.validator-v9.31.0+incompatible Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-go.uber.org.zap-v1.16.0 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-golang.org.x.sync-v0.0.0-20210220032951-036812b2e83c Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.magiconair.properties-v1.8.5 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.spf13.jwalterweatherman-v1.1.0 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.swag-v0.19.15 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.validate-v0.20.2 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.pelletier.go-toml-v1.9.3 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-gopkg.in.ini.v1-v1.62.0 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.asaskevich.govalidator-v0.0.0-20210307081110-f21760c49a8d Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.jedisct1.go-minisign-v0.0.0-20210414164026-819d7e2534ac Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.spf13.pflag-v1.0.5 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.zalando.go-keyring-v0.1.1 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-golang.org.x.term-v0.0.0-20210615171337-6886f2dfbf5b Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.golang.protobuf-v1.5.2 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.cyberphone.json-canonicalization-v0.0.0-20210303052042-6bc126869bf4 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.errors-v0.20.0 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.pkg.errors-v0.9.1 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.sigstore.sigstore-v0.0.0-20210609084117-386ea718fc64 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.spf13.viper-v1.7.1 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-google.golang.org.genproto-v0.0.0-20210617175327-b9e0b3197ced Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.mitchellh.go-homedir-v1.1.0 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.sassoftware.relic-v7.2.1+incompatible Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.spf13.cobra-v1.1.3 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-google.golang.org.grpc-v1.38.0 Relationship SPDXRef-Package-github.com.sigstore.rekor-v0.1.2-0.20210519014330-b5480728bde6 DEPENDS_ON SPDXRef-Package-github.com.fsnotify.fsnotify-v1.4.9 ##### Package representing the github.com/google/certificate-transparency-go PackageName: github.com/google/certificate-transparency-go SPDXID: SPDXRef-Package-github.com.google.certificate-transparency-go-v1.1.1 PackageVersion: v1.1.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 095ae65cdc8f710c01a841546db2d13d47decc49a7270c94e86351ef3a0cad8f PackageHomePage: https://github.com/google/certificate-transparency-go PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.google.certificate-transparency-go-v1.1.1 DEPENDS_ON SPDXRef-Package-google.golang.org.protobuf-v1.26.0 Relationship SPDXRef-Package-github.com.google.certificate-transparency-go-v1.1.1 DEPENDS_ON SPDXRef-Package-github.com.golang.groupcache-v0.0.0-20210331224755-41bb18bfe9da Relationship SPDXRef-Package-github.com.google.certificate-transparency-go-v1.1.1 DEPENDS_ON SPDXRef-Package-github.com.google.trillian-v1.3.14-0.20210413093047-5e12fb368c8f Relationship SPDXRef-Package-github.com.google.certificate-transparency-go-v1.1.1 DEPENDS_ON SPDXRef-Package-github.com.spf13.cobra-v1.1.3 Relationship SPDXRef-Package-github.com.google.certificate-transparency-go-v1.1.1 DEPENDS_ON SPDXRef-Package-google.golang.org.api-v0.46.0 Relationship SPDXRef-Package-github.com.google.certificate-transparency-go-v1.1.1 DEPENDS_ON SPDXRef-Package-google.golang.org.grpc-v1.38.0 Relationship SPDXRef-Package-github.com.google.certificate-transparency-go-v1.1.1 DEPENDS_ON SPDXRef-Package-github.com.mattn.go-runewidth-v0.0.9 Relationship SPDXRef-Package-github.com.google.certificate-transparency-go-v1.1.1 DEPENDS_ON SPDXRef-Package-go.uber.org.multierr-v1.7.0 Relationship SPDXRef-Package-github.com.google.certificate-transparency-go-v1.1.1 DEPENDS_ON SPDXRef-Package-go.uber.org.zap-v1.16.0 Relationship SPDXRef-Package-github.com.google.certificate-transparency-go-v1.1.1 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-github.com.google.certificate-transparency-go-v1.1.1 DEPENDS_ON SPDXRef-Package-github.com.golang.protobuf-v1.5.2 Relationship SPDXRef-Package-github.com.google.certificate-transparency-go-v1.1.1 DEPENDS_ON SPDXRef-Package-github.com.google.go-cmp-v0.5.6 Relationship SPDXRef-Package-github.com.google.certificate-transparency-go-v1.1.1 DEPENDS_ON SPDXRef-Package-google.golang.org.genproto-v0.0.0-20210617175327-b9e0b3197ced Relationship SPDXRef-Package-github.com.google.certificate-transparency-go-v1.1.1 DEPENDS_ON SPDXRef-Package-github.com.olekukonko.tablewriter-v0.0.5 Relationship SPDXRef-Package-github.com.google.certificate-transparency-go-v1.1.1 DEPENDS_ON SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 Relationship SPDXRef-Package-github.com.google.certificate-transparency-go-v1.1.1 DEPENDS_ON SPDXRef-Package-go.uber.org.atomic-v1.7.0 Relationship SPDXRef-Package-github.com.google.certificate-transparency-go-v1.1.1 DEPENDS_ON SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e ##### Package representing the google.golang.org/protobuf PackageName: google.golang.org/protobuf SPDXID: SPDXRef-Package-google.golang.org.protobuf-v1.26.0 PackageVersion: v1.26.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 121dc87761410a8622800b896b6f77b5b8ce26bd2484bcf85c8d6fd177116df1 PackageHomePage: https://google.golang.org/protobuf PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-google.golang.org.protobuf-v1.26.0 DEPENDS_ON SPDXRef-Package-github.com.golang.protobuf-v1.5.2 Relationship SPDXRef-Package-google.golang.org.protobuf-v1.26.0 DEPENDS_ON SPDXRef-Package-github.com.google.go-cmp-v0.5.6 Relationship SPDXRef-Package-google.golang.org.protobuf-v1.26.0 DEPENDS_ON SPDXRef-Package-google.golang.org.genproto-v0.0.0-20210617175327-b9e0b3197ced ##### Package representing the github.com/golang/protobuf PackageName: github.com/golang/protobuf SPDXID: SPDXRef-Package-github.com.golang.protobuf-v1.5.2 PackageVersion: v1.5.2 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 6f2a16bbef47f86415aa7ab887df08d30c1d4e79917c370fe163dbf5b8bde6b8 PackageHomePage: https://github.com/golang/protobuf PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.golang.protobuf-v1.5.2 DEPENDS_ON SPDXRef-Package-github.com.google.go-cmp-v0.5.6 Relationship SPDXRef-Package-github.com.golang.protobuf-v1.5.2 DEPENDS_ON SPDXRef-Package-google.golang.org.protobuf-v1.26.0 ##### Package representing the google.golang.org/genproto PackageName: google.golang.org/genproto SPDXID: SPDXRef-Package-google.golang.org.genproto-v0.0.0-20210617175327-b9e0b3197ced PackageVersion: v0.0.0-20210617175327-b9e0b3197ced PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: fb5b2471725d8be3b0a0d39775d6379681c484e5320f1c28007c425e0dccda4c PackageHomePage: https://google.golang.org/genproto PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-google.golang.org.genproto-v0.0.0-20210617175327-b9e0b3197ced DEPENDS_ON SPDXRef-Package-google.golang.org.protobuf-v1.26.0 Relationship SPDXRef-Package-google.golang.org.genproto-v0.0.0-20210617175327-b9e0b3197ced DEPENDS_ON SPDXRef-Package-golang.org.x.sync-v0.0.0-20210220032951-036812b2e83c Relationship SPDXRef-Package-google.golang.org.genproto-v0.0.0-20210617175327-b9e0b3197ced DEPENDS_ON SPDXRef-Package-github.com.golang.protobuf-v1.5.2 Relationship SPDXRef-Package-google.golang.org.genproto-v0.0.0-20210617175327-b9e0b3197ced DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-google.golang.org.genproto-v0.0.0-20210617175327-b9e0b3197ced DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 Relationship SPDXRef-Package-google.golang.org.genproto-v0.0.0-20210617175327-b9e0b3197ced DEPENDS_ON SPDXRef-Package-golang.org.x.text-v0.3.6 Relationship SPDXRef-Package-google.golang.org.genproto-v0.0.0-20210617175327-b9e0b3197ced DEPENDS_ON SPDXRef-Package-google.golang.org.grpc-v1.38.0 ##### Package representing the google.golang.org/grpc PackageName: google.golang.org/grpc SPDXID: SPDXRef-Package-google.golang.org.grpc-v1.38.0 PackageVersion: v1.38.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 28897ebd9d678ee15f24ce7808810c9c1ae39317687b00a4bb5555ae1627ee8d PackageHomePage: https://google.golang.org/grpc PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-google.golang.org.grpc-v1.38.0 DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 Relationship SPDXRef-Package-google.golang.org.grpc-v1.38.0 DEPENDS_ON SPDXRef-Package-google.golang.org.protobuf-v1.26.0 Relationship SPDXRef-Package-google.golang.org.grpc-v1.38.0 DEPENDS_ON SPDXRef-Package-cloud.google.com.go-v0.81.0 Relationship SPDXRef-Package-google.golang.org.grpc-v1.38.0 DEPENDS_ON SPDXRef-Package-golang.org.x.text-v0.3.6 Relationship SPDXRef-Package-google.golang.org.grpc-v1.38.0 DEPENDS_ON SPDXRef-Package-golang.org.x.oauth2-v0.0.0-20210514164344-f6687ab2804c Relationship SPDXRef-Package-google.golang.org.grpc-v1.38.0 DEPENDS_ON SPDXRef-Package-github.com.google.go-cmp-v0.5.6 Relationship SPDXRef-Package-google.golang.org.grpc-v1.38.0 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-google.golang.org.grpc-v1.38.0 DEPENDS_ON SPDXRef-Package-google.golang.org.genproto-v0.0.0-20210617175327-b9e0b3197ced Relationship SPDXRef-Package-google.golang.org.grpc-v1.38.0 DEPENDS_ON SPDXRef-Package-golang.org.x.sync-v0.0.0-20210220032951-036812b2e83c Relationship SPDXRef-Package-google.golang.org.grpc-v1.38.0 DEPENDS_ON SPDXRef-Package-github.com.gogo.protobuf-v1.3.2 Relationship SPDXRef-Package-google.golang.org.grpc-v1.38.0 DEPENDS_ON SPDXRef-Package-github.com.golang.protobuf-v1.5.2 ##### Package representing the github.com/go-chi/chi PackageName: github.com/go-chi/chi SPDXID: SPDXRef-Package-github.com.go-chi.chi-v4.1.2+incompatible PackageVersion: v4.1.2+incompatible PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 6c946a8dec9d21da32b4210fa7978a5cb94dfc2b1fb036486163d2da9c089ff9 PackageHomePage: https://github.com/go-chi/chi PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the go.uber.org/atomic PackageName: go.uber.org/atomic SPDXID: SPDXRef-Package-go.uber.org.atomic-v1.7.0 PackageVersion: v1.7.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 82f23ad2d95732cc976adb89249921f6115a4dd137b10fd3032b1bd71474c7f5 PackageHomePage: https://go.uber.org/atomic PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-go.uber.org.atomic-v1.7.0 DEPENDS_ON SPDXRef-Package-github.com.davecgh.go-spew-v1.1.1 ##### Package representing the go.uber.org/multierr PackageName: go.uber.org/multierr SPDXID: SPDXRef-Package-go.uber.org.multierr-v1.7.0 PackageVersion: v1.7.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 4bb6aa0b6cfb40ba982ee2226c46e4c582181690d25a68e8656b44e5013caeca PackageHomePage: https://go.uber.org/multierr PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-go.uber.org.multierr-v1.7.0 DEPENDS_ON SPDXRef-Package-go.uber.org.atomic-v1.7.0 ##### Package representing the go.uber.org/zap PackageName: go.uber.org/zap SPDXID: SPDXRef-Package-go.uber.org.zap-v1.16.0 PackageVersion: v1.16.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: cfd512fe5f2bc6c885d192cbe1db866a46527acce9adebaf598e8928418b9c08 PackageHomePage: https://go.uber.org/zap PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-go.uber.org.zap-v1.16.0 DEPENDS_ON SPDXRef-Package-go.uber.org.multierr-v1.7.0 Relationship SPDXRef-Package-go.uber.org.zap-v1.16.0 DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 Relationship SPDXRef-Package-go.uber.org.zap-v1.16.0 DEPENDS_ON SPDXRef-Package-github.com.pkg.errors-v0.9.1 Relationship SPDXRef-Package-go.uber.org.zap-v1.16.0 DEPENDS_ON SPDXRef-Package-go.uber.org.atomic-v1.7.0 ##### Package representing the github.com/blang/semver PackageName: github.com/blang/semver SPDXID: SPDXRef-Package-github.com.blang.semver-v3.5.1+incompatible PackageVersion: v3.5.1+incompatible PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 668ac29febf2c8c7e99d84eb10030d39ca9042980df35475ef75ea1b5145d258 PackageHomePage: https://github.com/blang/semver PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the golang.org/x/term PackageName: golang.org/x/term SPDXID: SPDXRef-Package-golang.org.x.term-v0.0.0-20210615171337-6886f2dfbf5b PackageVersion: v0.0.0-20210615171337-6886f2dfbf5b PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 8ee37192f7d4533352609092a0ce86b686643bae42cb6eb70eeaa09b46a50666 PackageHomePage: https://golang.org/x/term PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-golang.org.x.term-v0.0.0-20210615171337-6886f2dfbf5b DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 ##### Package representing the golang.org/x/crypto PackageName: golang.org/x/crypto SPDXID: SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e PackageVersion: v0.0.0-20210616213533-5ff15b29337e PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 711b1960550951ba9f896f4a6cf9b9277385e2acc66930be13a94323edd1c81f PackageHomePage: https://golang.org/x/crypto PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 Relationship SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e DEPENDS_ON SPDXRef-Package-golang.org.x.term-v0.0.0-20210615171337-6886f2dfbf5b Relationship SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e DEPENDS_ON SPDXRef-Package-golang.org.x.text-v0.3.6 ##### Package representing the github.com/howeyc/gopass PackageName: github.com/howeyc/gopass SPDXID: SPDXRef-Package-github.com.howeyc.gopass-v0.0.0-20190910152052-7cb4b85ec19c PackageVersion: v0.0.0-20190910152052-7cb4b85ec19c PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 9d00d401b09f8d272a15d65b242541ed5acbf7b91a9dda6a75e58e5e1248f79f PackageHomePage: https://github.com/howeyc/gopass PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/zalando/go-keyring PackageName: github.com/zalando/go-keyring SPDXID: SPDXRef-Package-github.com.zalando.go-keyring-v0.1.1 PackageVersion: v0.1.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 8a3f321827a4aeb85811bae37d83c6e438242a888f45552e22b596e8285168c3 PackageHomePage: https://github.com/zalando/go-keyring PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/sassoftware/relic PackageName: github.com/sassoftware/relic SPDXID: SPDXRef-Package-github.com.sassoftware.relic-v7.2.1+incompatible PackageVersion: v7.2.1+incompatible PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 1ba58336c70227b09e6b95fee0fe3dd77e3e7e75538635595eb8caba7788eadb PackageHomePage: https://github.com/sassoftware/relic PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/jedisct1/go-minisign PackageName: github.com/jedisct1/go-minisign SPDXID: SPDXRef-Package-github.com.jedisct1.go-minisign-v0.0.0-20210414164026-819d7e2534ac PackageVersion: v0.0.0-20210414164026-819d7e2534ac PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 5c51edc535c9ef254999ddd03ca153a667e97ceebc9d78810dd74407186dd5c6 PackageHomePage: https://github.com/jedisct1/go-minisign PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.jedisct1.go-minisign-v0.0.0-20210414164026-819d7e2534ac DEPENDS_ON SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e ##### Package representing the github.com/ghodss/yaml PackageName: github.com/ghodss/yaml SPDXID: SPDXRef-Package-github.com.ghodss.yaml-v1.0.0 PackageVersion: v1.0.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 8a601d3cc973a9e45f3c1c56f28377edf7d28cabaaca1668dce782c4607afdaa PackageHomePage: https://github.com/ghodss/yaml PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/cavaliercoder/go-rpm PackageName: github.com/cavaliercoder/go-rpm SPDXID: SPDXRef-Package-github.com.cavaliercoder.go-rpm-v0.0.0-20200122174316-8cb9fd9c31a8 PackageVersion: v0.0.0-20200122174316-8cb9fd9c31a8 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 57cfc0c523cf3587fa4bc6430836c8da25b057b26826fb08b5d8b80964ae4ced PackageHomePage: https://github.com/cavaliercoder/go-rpm PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/googleapis/gax-go/v2 PackageName: github.com/googleapis/gax-go/v2 SPDXID: SPDXRef-Package-github.com.googleapis.gax-go.v2-v2.0.5 PackageVersion: v2.0.5 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: b8b7e67cfe0beb74db70984ea7278c8a2644f7190000b0230a603cf73db9be94 PackageHomePage: https://github.com/googleapis/gax-go/v2 PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.googleapis.gax-go.v2-v2.0.5 DEPENDS_ON SPDXRef-Package-google.golang.org.grpc-v1.38.0 ##### Package representing the cloud.google.com/go PackageName: cloud.google.com/go SPDXID: SPDXRef-Package-cloud.google.com.go-v0.81.0 PackageVersion: v0.81.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 459733de8ac4d0d69eba97f5e4f4050395c9d9d05e6cba633e9247c7588232e9 PackageHomePage: https://cloud.google.com/go PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-cloud.google.com.go-v0.81.0 DEPENDS_ON SPDXRef-Package-golang.org.x.oauth2-v0.0.0-20210514164344-f6687ab2804c Relationship SPDXRef-Package-cloud.google.com.go-v0.81.0 DEPENDS_ON SPDXRef-Package-go.opencensus.io-v0.23.0 Relationship SPDXRef-Package-cloud.google.com.go-v0.81.0 DEPENDS_ON SPDXRef-Package-github.com.googleapis.gax-go.v2-v2.0.5 Relationship SPDXRef-Package-cloud.google.com.go-v0.81.0 DEPENDS_ON SPDXRef-Package-golang.org.x.time-v0.0.0-20210220033141-f8bda1e9f3ba Relationship SPDXRef-Package-cloud.google.com.go-v0.81.0 DEPENDS_ON SPDXRef-Package-google.golang.org.grpc-v1.38.0 Relationship SPDXRef-Package-cloud.google.com.go-v0.81.0 DEPENDS_ON SPDXRef-Package-google.golang.org.api-v0.46.0 Relationship SPDXRef-Package-cloud.google.com.go-v0.81.0 DEPENDS_ON SPDXRef-Package-github.com.golang.protobuf-v1.5.2 Relationship SPDXRef-Package-cloud.google.com.go-v0.81.0 DEPENDS_ON SPDXRef-Package-golang.org.x.text-v0.3.6 Relationship SPDXRef-Package-cloud.google.com.go-v0.81.0 DEPENDS_ON SPDXRef-Package-github.com.google.go-cmp-v0.5.6 Relationship SPDXRef-Package-cloud.google.com.go-v0.81.0 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-cloud.google.com.go-v0.81.0 DEPENDS_ON SPDXRef-Package-golang.org.x.sync-v0.0.0-20210220032951-036812b2e83c Relationship SPDXRef-Package-cloud.google.com.go-v0.81.0 DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 Relationship SPDXRef-Package-cloud.google.com.go-v0.81.0 DEPENDS_ON SPDXRef-Package-github.com.golang.groupcache-v0.0.0-20210331224755-41bb18bfe9da Relationship SPDXRef-Package-cloud.google.com.go-v0.81.0 DEPENDS_ON SPDXRef-Package-google.golang.org.genproto-v0.0.0-20210617175327-b9e0b3197ced Relationship SPDXRef-Package-cloud.google.com.go-v0.81.0 DEPENDS_ON SPDXRef-Package-google.golang.org.protobuf-v1.26.0 ##### Package representing the google.golang.org/api PackageName: google.golang.org/api SPDXID: SPDXRef-Package-google.golang.org.api-v0.46.0 PackageVersion: v0.46.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 9c27d3b7b736de1570971331811b59458ba57cf5d2cb57263c5c1b9cc1c4c474 PackageHomePage: https://google.golang.org/api PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-google.golang.org.api-v0.46.0 DEPENDS_ON SPDXRef-Package-go.opencensus.io-v0.23.0 Relationship SPDXRef-Package-google.golang.org.api-v0.46.0 DEPENDS_ON SPDXRef-Package-google.golang.org.grpc-v1.38.0 Relationship SPDXRef-Package-google.golang.org.api-v0.46.0 DEPENDS_ON SPDXRef-Package-golang.org.x.text-v0.3.6 Relationship SPDXRef-Package-google.golang.org.api-v0.46.0 DEPENDS_ON SPDXRef-Package-google.golang.org.genproto-v0.0.0-20210617175327-b9e0b3197ced Relationship SPDXRef-Package-google.golang.org.api-v0.46.0 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-google.golang.org.api-v0.46.0 DEPENDS_ON SPDXRef-Package-cloud.google.com.go-v0.81.0 Relationship SPDXRef-Package-google.golang.org.api-v0.46.0 DEPENDS_ON SPDXRef-Package-github.com.google.go-cmp-v0.5.6 Relationship SPDXRef-Package-google.golang.org.api-v0.46.0 DEPENDS_ON SPDXRef-Package-github.com.googleapis.gax-go.v2-v2.0.5 Relationship SPDXRef-Package-google.golang.org.api-v0.46.0 DEPENDS_ON SPDXRef-Package-golang.org.x.oauth2-v0.0.0-20210514164344-f6687ab2804c Relationship SPDXRef-Package-google.golang.org.api-v0.46.0 DEPENDS_ON SPDXRef-Package-golang.org.x.sync-v0.0.0-20210220032951-036812b2e83c Relationship SPDXRef-Package-google.golang.org.api-v0.46.0 DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 Relationship SPDXRef-Package-google.golang.org.api-v0.46.0 DEPENDS_ON SPDXRef-Package-github.com.golang.protobuf-v1.5.2 ##### Package representing the golang.org/x/oauth2 PackageName: golang.org/x/oauth2 SPDXID: SPDXRef-Package-golang.org.x.oauth2-v0.0.0-20210514164344-f6687ab2804c PackageVersion: v0.0.0-20210514164344-f6687ab2804c PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 334a2a1b320de68c665dfdb61282dad09b343cd93b494ac1241522898bf253d3 PackageHomePage: https://golang.org/x/oauth2 PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-golang.org.x.oauth2-v0.0.0-20210514164344-f6687ab2804c DEPENDS_ON SPDXRef-Package-cloud.google.com.go-v0.81.0 Relationship SPDXRef-Package-golang.org.x.oauth2-v0.0.0-20210514164344-f6687ab2804c DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-golang.org.x.oauth2-v0.0.0-20210514164344-f6687ab2804c DEPENDS_ON SPDXRef-Package-golang.org.x.sync-v0.0.0-20210220032951-036812b2e83c ##### Package representing the go.opencensus.io PackageName: go.opencensus.io SPDXID: SPDXRef-Package-go.opencensus.io-v0.23.0 PackageVersion: v0.23.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 7c86fbad22be2d27398183a1288e4c2aabd20d14271492cd47651f23d3139bd6 PackageHomePage: https://go.opencensus.io PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-go.opencensus.io-v0.23.0 DEPENDS_ON SPDXRef-Package-golang.org.x.text-v0.3.6 Relationship SPDXRef-Package-go.opencensus.io-v0.23.0 DEPENDS_ON SPDXRef-Package-google.golang.org.genproto-v0.0.0-20210617175327-b9e0b3197ced Relationship SPDXRef-Package-go.opencensus.io-v0.23.0 DEPENDS_ON SPDXRef-Package-google.golang.org.api-v0.46.0 Relationship SPDXRef-Package-go.opencensus.io-v0.23.0 DEPENDS_ON SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 Relationship SPDXRef-Package-go.opencensus.io-v0.23.0 DEPENDS_ON SPDXRef-Package-google.golang.org.grpc-v1.38.0 Relationship SPDXRef-Package-go.opencensus.io-v0.23.0 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-go.opencensus.io-v0.23.0 DEPENDS_ON SPDXRef-Package-github.com.golang.protobuf-v1.5.2 Relationship SPDXRef-Package-go.opencensus.io-v0.23.0 DEPENDS_ON SPDXRef-Package-github.com.google.go-cmp-v0.5.6 Relationship SPDXRef-Package-go.opencensus.io-v0.23.0 DEPENDS_ON SPDXRef-Package-github.com.golang.groupcache-v0.0.0-20210331224755-41bb18bfe9da Relationship SPDXRef-Package-go.opencensus.io-v0.23.0 DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 ##### Package representing the github.com/golang/groupcache PackageName: github.com/golang/groupcache SPDXID: SPDXRef-Package-github.com.golang.groupcache-v0.0.0-20210331224755-41bb18bfe9da PackageVersion: v0.0.0-20210331224755-41bb18bfe9da PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 03f65147877c2e0084097490c88ede91762bc954dd9dcf77ddaf822ffc1ac168 PackageHomePage: https://github.com/golang/groupcache PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/google/go-cmp PackageName: github.com/google/go-cmp SPDXID: SPDXRef-Package-github.com.google.go-cmp-v0.5.6 PackageVersion: v0.5.6 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: e95afd232d9a38271d4252ccccc027ddc13aaea55345ca12be0df6462bb75687 PackageHomePage: https://github.com/google/go-cmp PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/hashicorp/errwrap PackageName: github.com/hashicorp/errwrap SPDXID: SPDXRef-Package-github.com.hashicorp.errwrap-v1.1.0 PackageVersion: v1.1.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 047a321b836f7f66764f46fc2887ac21a3eac0b22b6c8fb8896fab7db6da622f PackageHomePage: https://github.com/hashicorp/errwrap PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/hashicorp/go-cleanhttp PackageName: github.com/hashicorp/go-cleanhttp SPDXID: SPDXRef-Package-github.com.hashicorp.go-cleanhttp-v0.5.2 PackageVersion: v0.5.2 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 850ecf5976cd640a31d2c94b7fe0fddeb3b40186965f372ad54a254e3bd0dd8f PackageHomePage: https://github.com/hashicorp/go-cleanhttp PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/hashicorp/go-multierror PackageName: github.com/hashicorp/go-multierror SPDXID: SPDXRef-Package-github.com.hashicorp.go-multierror-v1.1.1 PackageVersion: v1.1.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: f903a790c3fd699e65977baa2c4bb911282266395b92a232e0ceeafc38b1eaf2 PackageHomePage: https://github.com/hashicorp/go-multierror PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.hashicorp.go-multierror-v1.1.1 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.errwrap-v1.1.0 ##### Package representing the github.com/hashicorp/go-retryablehttp PackageName: github.com/hashicorp/go-retryablehttp SPDXID: SPDXRef-Package-github.com.hashicorp.go-retryablehttp-v0.6.8 PackageVersion: v0.6.8 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 7b1c176e794c9eac1776346636ac0f6a6e4b592a092d6263d518e2a230d7461c PackageHomePage: https://github.com/hashicorp/go-retryablehttp PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.hashicorp.go-retryablehttp-v0.6.8 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.go-cleanhttp-v0.5.2 ##### Package representing the github.com/hashicorp/go-rootcerts PackageName: github.com/hashicorp/go-rootcerts SPDXID: SPDXRef-Package-github.com.hashicorp.go-rootcerts-v1.0.2 PackageVersion: v1.0.2 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: d42cdbf7b568f432127ee9d549060acbfb08ab2a527d059e0e12e84224d9b590 PackageHomePage: https://github.com/hashicorp/go-rootcerts PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.hashicorp.go-rootcerts-v1.0.2 DEPENDS_ON SPDXRef-Package-github.com.mitchellh.go-homedir-v1.1.0 ##### Package representing the github.com/hashicorp/vault/sdk PackageName: github.com/hashicorp/vault/sdk SPDXID: SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 PackageVersion: v0.2.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 21e28009edebedb97dc5fc5d340838c747e25934dc1606af952be083cd9c6c66 PackageHomePage: https://github.com/hashicorp/vault/sdk PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.errwrap-v1.1.0 Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.go-cleanhttp-v0.5.2 Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-github.com.mitchellh.mapstructure-v1.4.1 Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-github.com.opencontainers.image-spec-v1.0.1 Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-github.com.pierrec.lz4-v2.6.0+incompatible Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-golang.org.x.time-v0.0.0-20210220033141-f8bda1e9f3ba Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-github.com.docker.distribution-v2.7.1+incompatible Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-github.com.gorilla.mux-v1.8.0 Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.vault.api-v1.1.0 Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-github.com.opencontainers.go-digest-v1.0.0 Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-google.golang.org.protobuf-v1.26.0 Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-github.com.golang.protobuf-v1.5.2 Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.go-sockaddr-v1.0.2 Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-github.com.pkg.errors-v0.9.1 Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-github.com.ryanuber.go-glob-v1.0.0 Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-github.com.docker.docker-v1.4.2-0.20200319182547-c7ad2b866182 Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.go-multierror-v1.1.1 Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.hcl-v1.0.0 Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-google.golang.org.grpc-v1.38.0 Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-gopkg.in.square.go-jose.v2-v2.5.1 Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-github.com.golang.snappy-v0.0.3 Relationship SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.go-retryablehttp-v0.6.8 ##### Package representing the github.com/golang/snappy PackageName: github.com/golang/snappy SPDXID: SPDXRef-Package-github.com.golang.snappy-v0.0.3 PackageVersion: v0.0.3 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: ec86cb9791c62c2bc5f0f9dd332d61198c4cf6f40818e67135a45cde051b40b4 PackageHomePage: https://github.com/golang/snappy PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/pierrec/lz4 PackageName: github.com/pierrec/lz4 SPDXID: SPDXRef-Package-github.com.pierrec.lz4-v2.6.0+incompatible PackageVersion: v2.6.0+incompatible PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 4de292b0e083fe4176c7b02ae284a4b4c24c88744cfa0398f94b0d2229184192 PackageHomePage: https://github.com/pierrec/lz4 PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/hashicorp/go-sockaddr PackageName: github.com/hashicorp/go-sockaddr SPDXID: SPDXRef-Package-github.com.hashicorp.go-sockaddr-v1.0.2 PackageVersion: v1.0.2 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 3b91d4c2b863af23838e2f6b983ffe9c2cf4741995ce97e6ecf781876443ccc9 PackageHomePage: https://github.com/hashicorp/go-sockaddr PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.hashicorp.go-sockaddr-v1.0.2 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.errwrap-v1.1.0 ##### Package representing the github.com/ryanuber/go-glob PackageName: github.com/ryanuber/go-glob SPDXID: SPDXRef-Package-github.com.ryanuber.go-glob-v1.0.0 PackageVersion: v1.0.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: e4a59b9bcddd0bfaebb26f2cd34aae2c85f80acf9d97c5cc6e98a262a3deefbd PackageHomePage: https://github.com/ryanuber/go-glob PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the golang.org/x/time PackageName: golang.org/x/time SPDXID: SPDXRef-Package-golang.org.x.time-v0.0.0-20210220033141-f8bda1e9f3ba PackageVersion: v0.0.0-20210220033141-f8bda1e9f3ba PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 9eb556e6f8c487b07629dbd90cf04320501894e9f491d2a22b89593e28e24df2 PackageHomePage: https://golang.org/x/time PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the gopkg.in/square/go-jose.v2 PackageName: gopkg.in/square/go-jose.v2 SPDXID: SPDXRef-Package-gopkg.in.square.go-jose.v2-v2.5.1 PackageVersion: v2.5.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: b35860f881c48c56d045f6600a446bc8ccb4d849932abdb2a4b5bb8d3efd14a2 PackageHomePage: https://gopkg.in/square/go-jose.v2 PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/hashicorp/vault/api PackageName: github.com/hashicorp/vault/api SPDXID: SPDXRef-Package-github.com.hashicorp.vault.api-v1.1.0 PackageVersion: v1.1.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 7384684d18b6cdf97e9ac93b246657168a65f656a5ef7501e5972de8f20b25b6 PackageHomePage: https://github.com/hashicorp/vault/api PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.hashicorp.vault.api-v1.1.0 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.go-cleanhttp-v0.5.2 Relationship SPDXRef-Package-github.com.hashicorp.vault.api-v1.1.0 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.go-multierror-v1.1.1 Relationship SPDXRef-Package-github.com.hashicorp.vault.api-v1.1.0 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.go-retryablehttp-v0.6.8 Relationship SPDXRef-Package-github.com.hashicorp.vault.api-v1.1.0 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.go-rootcerts-v1.0.2 Relationship SPDXRef-Package-github.com.hashicorp.vault.api-v1.1.0 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.vault.sdk-v0.2.0 Relationship SPDXRef-Package-github.com.hashicorp.vault.api-v1.1.0 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-github.com.hashicorp.vault.api-v1.1.0 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.errwrap-v1.1.0 Relationship SPDXRef-Package-github.com.hashicorp.vault.api-v1.1.0 DEPENDS_ON SPDXRef-Package-github.com.hashicorp.hcl-v1.0.0 Relationship SPDXRef-Package-github.com.hashicorp.vault.api-v1.1.0 DEPENDS_ON SPDXRef-Package-github.com.mitchellh.mapstructure-v1.4.1 Relationship SPDXRef-Package-github.com.hashicorp.vault.api-v1.1.0 DEPENDS_ON SPDXRef-Package-golang.org.x.time-v0.0.0-20210220033141-f8bda1e9f3ba Relationship SPDXRef-Package-github.com.hashicorp.vault.api-v1.1.0 DEPENDS_ON SPDXRef-Package-gopkg.in.square.go-jose.v2-v2.5.1 ##### Package representing the github.com/theupdateframework/go-tuf PackageName: github.com/theupdateframework/go-tuf SPDXID: SPDXRef-Package-github.com.theupdateframework.go-tuf-v0.0.0-20201230183259-aee6270feb55 PackageVersion: v0.0.0-20201230183259-aee6270feb55 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: ed391d786e0359002979453c3fc82a8eadf5e3e275ef4a15027a9e9147644262 PackageHomePage: https://github.com/theupdateframework/go-tuf PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.theupdateframework.go-tuf-v0.0.0-20201230183259-aee6270feb55 DEPENDS_ON SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e ##### Package representing the github.com/coreos/go-oidc/v3 PackageName: github.com/coreos/go-oidc/v3 SPDXID: SPDXRef-Package-github.com.coreos.go-oidc.v3-v3.0.0 PackageVersion: v3.0.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 9b01858cab936242c2c4957f7c158cd678af5eb7151bd2af80f33eef9ec12ad2 PackageHomePage: https://github.com/coreos/go-oidc/v3 PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.coreos.go-oidc.v3-v3.0.0 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-github.com.coreos.go-oidc.v3-v3.0.0 DEPENDS_ON SPDXRef-Package-golang.org.x.oauth2-v0.0.0-20210514164344-f6687ab2804c Relationship SPDXRef-Package-github.com.coreos.go-oidc.v3-v3.0.0 DEPENDS_ON SPDXRef-Package-gopkg.in.square.go-jose.v2-v2.5.1 Relationship SPDXRef-Package-github.com.coreos.go-oidc.v3-v3.0.0 DEPENDS_ON SPDXRef-Package-github.com.google.go-cmp-v0.5.6 ##### Package representing the github.com/sigstore/fulcio PackageName: github.com/sigstore/fulcio SPDXID: SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca PackageVersion: v0.0.0-20210405115948-e7630f533fca PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: e9fed9477691b8fbffc2f6bef6ca60b9f167db0cb53898280b49cfd930a54e05 PackageHomePage: https://github.com/sigstore/fulcio PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-google.golang.org.genproto-v0.0.0-20210617175327-b9e0b3197ced Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-go.uber.org.zap-v1.16.0 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.pelletier.go-toml-v1.9.3 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-cloud.google.com.go-v0.81.0 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-google.golang.org.protobuf-v1.26.0 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.go-openapi.loads-v0.20.2 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.go-openapi.errors-v0.20.0 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.go-openapi.strfmt-v0.20.1 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.mailru.easyjson-v0.7.7 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.spf13.afero-v1.6.0 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.spf13.jwalterweatherman-v1.1.0 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.spf13.cobra-v1.1.3 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.mitchellh.mapstructure-v1.4.1 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.go-openapi.spec-v0.20.3 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.go-openapi.runtime-v0.19.29 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.spf13.viper-v1.7.1 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.go-openapi.swag-v0.19.15 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.go-chi.chi-v4.1.2+incompatible Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.fsnotify.fsnotify-v1.4.9 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.coreos.go-oidc.v3-v3.0.0 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.magiconair.properties-v1.8.5 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-golang.org.x.oauth2-v0.0.0-20210514164344-f6687ab2804c Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.segmentio.ksuid-v1.0.3 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.mitchellh.go-homedir-v1.1.0 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-gopkg.in.ini.v1-v1.62.0 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.spf13.pflag-v1.0.5 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.spf13.cast-v1.3.1 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.skratchdot.open-golang-v0.0.0-20200116055534-eef842397966 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-github.com.go-openapi.validate-v0.20.2 Relationship SPDXRef-Package-github.com.sigstore.fulcio-v0.0.0-20210405115948-e7630f533fca DEPENDS_ON SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e ##### Package representing the github.com/segmentio/ksuid PackageName: github.com/segmentio/ksuid SPDXID: SPDXRef-Package-github.com.segmentio.ksuid-v1.0.3 PackageVersion: v1.0.3 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 58179fe001a088e616b1848aec64d6fd5c8a8e79e88856e58812b58f3835500d PackageHomePage: https://github.com/segmentio/ksuid PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/skratchdot/open-golang PackageName: github.com/skratchdot/open-golang SPDXID: SPDXRef-Package-github.com.skratchdot.open-golang-v0.0.0-20200116055534-eef842397966 PackageVersion: v0.0.0-20200116055534-eef842397966 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 0977118b561a46782a4ec19fcf21d79280b78fde20bc3c77219e70d5aa878e46 PackageHomePage: https://github.com/skratchdot/open-golang PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/gogo/protobuf PackageName: github.com/gogo/protobuf SPDXID: SPDXRef-Package-github.com.gogo.protobuf-v1.3.2 PackageVersion: v1.3.2 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 95d3fe25fc8e393da0e7135467b6699f4d0bf5f62ac93014def07a6ebc840536 PackageHomePage: https://github.com/gogo/protobuf PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the gopkg.in/inf.v0 PackageName: gopkg.in/inf.v0 SPDXID: SPDXRef-Package-gopkg.in.inf.v0-v0.9.1 PackageVersion: v0.9.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 771fadad552618ff0ae1e08892c4c5e06bab75c14304e2dccdfa390dc2db2a86 PackageHomePage: https://gopkg.in/inf.v0 PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the k8s.io/apimachinery PackageName: k8s.io/apimachinery SPDXID: SPDXRef-Package-k8s.io.apimachinery-v0.21.2 PackageVersion: v0.21.2 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 99a73f202aa86722321431e4bd1cd3f88ed1d4e680cddbe4d1d16c1794a02c4e PackageHomePage: https://k8s.io/apimachinery PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-k8s.io.apimachinery-v0.21.2 DEPENDS_ON SPDXRef-Package-k8s.io.klog.v2-v2.8.0 Relationship SPDXRef-Package-k8s.io.apimachinery-v0.21.2 DEPENDS_ON SPDXRef-Package-sigs.k8s.io.structured-merge-diff.v4-v4.1.0 Relationship SPDXRef-Package-k8s.io.apimachinery-v0.21.2 DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 Relationship SPDXRef-Package-k8s.io.apimachinery-v0.21.2 DEPENDS_ON SPDXRef-Package-gopkg.in.inf.v0-v0.9.1 Relationship SPDXRef-Package-k8s.io.apimachinery-v0.21.2 DEPENDS_ON SPDXRef-Package-sigs.k8s.io.yaml-v1.2.0 Relationship SPDXRef-Package-k8s.io.apimachinery-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.pkg.errors-v0.9.1 Relationship SPDXRef-Package-k8s.io.apimachinery-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.json-iterator.go-v1.1.11 Relationship SPDXRef-Package-k8s.io.apimachinery-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.google.gofuzz-v1.2.0 Relationship SPDXRef-Package-k8s.io.apimachinery-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.gogo.protobuf-v1.3.2 Relationship SPDXRef-Package-k8s.io.apimachinery-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.davecgh.go-spew-v1.1.1 Relationship SPDXRef-Package-k8s.io.apimachinery-v0.21.2 DEPENDS_ON SPDXRef-Package-golang.org.x.text-v0.3.6 Relationship SPDXRef-Package-k8s.io.apimachinery-v0.21.2 DEPENDS_ON SPDXRef-Package-google.golang.org.protobuf-v1.26.0 Relationship SPDXRef-Package-k8s.io.apimachinery-v0.21.2 DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 Relationship SPDXRef-Package-k8s.io.apimachinery-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.spf13.pflag-v1.0.5 Relationship SPDXRef-Package-k8s.io.apimachinery-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.modern-go.reflect2-v1.0.1 Relationship SPDXRef-Package-k8s.io.apimachinery-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.golang.protobuf-v1.5.2 Relationship SPDXRef-Package-k8s.io.apimachinery-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.golang.groupcache-v0.0.0-20210331224755-41bb18bfe9da Relationship SPDXRef-Package-k8s.io.apimachinery-v0.21.2 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-k8s.io.apimachinery-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.googleapis.gnostic-v0.4.1 Relationship SPDXRef-Package-k8s.io.apimachinery-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.google.go-cmp-v0.5.6 ##### Package representing the github.com/google/gofuzz PackageName: github.com/google/gofuzz SPDXID: SPDXRef-Package-github.com.google.gofuzz-v1.2.0 PackageVersion: v1.2.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 9f90c7a974671a73dfacee0304a7b34959a807ae0dced51d0aa6f4883b296827 PackageHomePage: https://github.com/google/gofuzz PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/go-logr/logr PackageName: github.com/go-logr/logr SPDXID: SPDXRef-Package-github.com.go-logr.logr-v0.4.0 PackageVersion: v0.4.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 729410377448d47553cbc0b4dd2894ca3c1aa69e6426e18aa31f2bae3ab6a1c8 PackageHomePage: https://github.com/go-logr/logr PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the k8s.io/klog/v2 PackageName: k8s.io/klog/v2 SPDXID: SPDXRef-Package-k8s.io.klog.v2-v2.8.0 PackageVersion: v2.8.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: f3843055d8b518fac6bd96d36d10cda14ef347848023df47e0ae510cfc668c9d PackageHomePage: https://k8s.io/klog/v2 PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-k8s.io.klog.v2-v2.8.0 DEPENDS_ON SPDXRef-Package-github.com.go-logr.logr-v0.4.0 ##### Package representing the github.com/modern-go/concurrent PackageName: github.com/modern-go/concurrent SPDXID: SPDXRef-Package-github.com.modern-go.concurrent-v0.0.0-20180306012644-bacd9c7ef1dd PackageVersion: v0.0.0-20180306012644-bacd9c7ef1dd PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: c6081e6ce83b52eb5415b1eaaa3920fcbdff17d1c3fa789b5b89d2cbbc6ace2e PackageHomePage: https://github.com/modern-go/concurrent PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/modern-go/reflect2 PackageName: github.com/modern-go/reflect2 SPDXID: SPDXRef-Package-github.com.modern-go.reflect2-v1.0.1 PackageVersion: v1.0.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 95aa5db9774824ade90b1b53c29f23e331139bed8b757f2c715ea0efc7399fc8 PackageHomePage: https://github.com/modern-go/reflect2 PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/json-iterator/go PackageName: github.com/json-iterator/go SPDXID: SPDXRef-Package-github.com.json-iterator.go-v1.1.11 PackageVersion: v1.1.11 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 254625d8d2b1f7077ee5b424343f8a20c77e36b8d825fae1edf817949c9b3e84 PackageHomePage: https://github.com/json-iterator/go PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.json-iterator.go-v1.1.11 DEPENDS_ON SPDXRef-Package-github.com.davecgh.go-spew-v1.1.1 Relationship SPDXRef-Package-github.com.json-iterator.go-v1.1.11 DEPENDS_ON SPDXRef-Package-github.com.google.gofuzz-v1.2.0 Relationship SPDXRef-Package-github.com.json-iterator.go-v1.1.11 DEPENDS_ON SPDXRef-Package-github.com.modern-go.concurrent-v0.0.0-20180306012644-bacd9c7ef1dd Relationship SPDXRef-Package-github.com.json-iterator.go-v1.1.11 DEPENDS_ON SPDXRef-Package-github.com.modern-go.reflect2-v1.0.1 ##### Package representing the sigs.k8s.io/structured-merge-diff/v4 PackageName: sigs.k8s.io/structured-merge-diff/v4 SPDXID: SPDXRef-Package-sigs.k8s.io.structured-merge-diff.v4-v4.1.0 PackageVersion: v4.1.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 223818142048052ae7e0e13055d154f4e681983fa3fabd380ed59d459f9bbea7 PackageHomePage: https://sigs.k8s.io/structured-merge-diff/v4 PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-sigs.k8s.io.structured-merge-diff.v4-v4.1.0 DEPENDS_ON SPDXRef-Package-github.com.modern-go.concurrent-v0.0.0-20180306012644-bacd9c7ef1dd Relationship SPDXRef-Package-sigs.k8s.io.structured-merge-diff.v4-v4.1.0 DEPENDS_ON SPDXRef-Package-github.com.modern-go.reflect2-v1.0.1 Relationship SPDXRef-Package-sigs.k8s.io.structured-merge-diff.v4-v4.1.0 DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 Relationship SPDXRef-Package-sigs.k8s.io.structured-merge-diff.v4-v4.1.0 DEPENDS_ON SPDXRef-Package-github.com.google.gofuzz-v1.2.0 Relationship SPDXRef-Package-sigs.k8s.io.structured-merge-diff.v4-v4.1.0 DEPENDS_ON SPDXRef-Package-github.com.json-iterator.go-v1.1.11 ##### Package representing the k8s.io/api PackageName: k8s.io/api SPDXID: SPDXRef-Package-k8s.io.api-v0.21.2 PackageVersion: v0.21.2 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 0f91c64066f5e8b2de142b2d3b155d66d6edcf720aa0f30af9929be542aa6ffe PackageHomePage: https://k8s.io/api PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-k8s.io.api-v0.21.2 DEPENDS_ON SPDXRef-Package-k8s.io.apimachinery-v0.21.2 Relationship SPDXRef-Package-k8s.io.api-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.gogo.protobuf-v1.3.2 ##### Package representing the github.com/googleapis/gnostic PackageName: github.com/googleapis/gnostic SPDXID: SPDXRef-Package-github.com.googleapis.gnostic-v0.4.1 PackageVersion: v0.4.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 2e1455e8d4d3a3ca2c1429f4dfd223227c5d875a0b9fec12c7a8b6540e606a58 PackageHomePage: https://github.com/googleapis/gnostic PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.googleapis.gnostic-v0.4.1 DEPENDS_ON SPDXRef-Package-github.com.golang.protobuf-v1.5.2 Relationship SPDXRef-Package-github.com.googleapis.gnostic-v0.4.1 DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 ##### Package representing the sigs.k8s.io/yaml PackageName: sigs.k8s.io/yaml SPDXID: SPDXRef-Package-sigs.k8s.io.yaml-v1.2.0 PackageVersion: v1.2.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 76d8cd575a926fc427aa57cf0574548aac399ee84e3e313e841c1cccf99ffac7 PackageHomePage: https://sigs.k8s.io/yaml PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-sigs.k8s.io.yaml-v1.2.0 DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 Relationship SPDXRef-Package-sigs.k8s.io.yaml-v1.2.0 DEPENDS_ON SPDXRef-Package-github.com.davecgh.go-spew-v1.1.1 ##### Package representing the k8s.io/client-go PackageName: k8s.io/client-go SPDXID: SPDXRef-Package-k8s.io.client-go-v0.21.2 PackageVersion: v0.21.2 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 49c966ba6a48e4cb8e520ae8c8285d0d19fdf7706b4ba3f7e50acdcddaa560f3 PackageHomePage: https://k8s.io/client-go PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-golang.org.x.oauth2-v0.0.0-20210514164344-f6687ab2804c Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.davecgh.go-spew-v1.1.1 Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.googleapis.gnostic-v0.4.1 Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-golang.org.x.time-v0.0.0-20210220033141-f8bda1e9f3ba Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.imdario.mergo-v0.3.9 Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.Azure.go-autorest.autorest-v0.11.18 Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.Azure.go-autorest.autorest.adal-v0.9.13 Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.gogo.protobuf-v1.3.2 Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.google.gofuzz-v1.2.0 Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.spf13.pflag-v1.0.5 Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-golang.org.x.term-v0.0.0-20210615171337-6886f2dfbf5b Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-k8s.io.apimachinery-v0.21.2 Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-cloud.google.com.go-v0.81.0 Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.golang.groupcache-v0.0.0-20210331224755-41bb18bfe9da Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.google.go-cmp-v0.5.6 Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-sigs.k8s.io.yaml-v1.2.0 Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-k8s.io.utils-v0.0.0-20201110183641-67b214c5f920 Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-k8s.io.klog.v2-v2.8.0 Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-github.com.golang.protobuf-v1.5.2 Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-sigs.k8s.io.structured-merge-diff.v4-v4.1.0 Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-k8s.io.api-v0.21.2 Relationship SPDXRef-Package-k8s.io.client-go-v0.21.2 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 ##### Package representing the github.com/davecgh/go-spew PackageName: github.com/davecgh/go-spew SPDXID: SPDXRef-Package-github.com.davecgh.go-spew-v1.1.1 PackageVersion: v1.1.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 77d53af0a568b8c213c0a761194a7cb44abeb0c005359ec1b41ffdab10d7bb13 PackageHomePage: https://github.com/davecgh/go-spew PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the k8s.io/utils PackageName: k8s.io/utils SPDXID: SPDXRef-Package-k8s.io.utils-v0.0.0-20201110183641-67b214c5f920 PackageVersion: v0.0.0-20201110183641-67b214c5f920 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: e27d3708c47807fa1e142d0d0043af60498463f429ea0932ffc50249e3efa6c6 PackageHomePage: https://k8s.io/utils PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-k8s.io.utils-v0.0.0-20201110183641-67b214c5f920 DEPENDS_ON SPDXRef-Package-k8s.io.klog.v2-v2.8.0 Relationship SPDXRef-Package-k8s.io.utils-v0.0.0-20201110183641-67b214c5f920 DEPENDS_ON SPDXRef-Package-github.com.spf13.afero-v1.6.0 Relationship SPDXRef-Package-k8s.io.utils-v0.0.0-20201110183641-67b214c5f920 DEPENDS_ON SPDXRef-Package-github.com.davecgh.go-spew-v1.1.1 ##### Package representing the github.com/Azure/go-autorest/autorest/date PackageName: github.com/Azure/go-autorest/autorest/date SPDXID: SPDXRef-Package-github.com.Azure.go-autorest.autorest.date-v0.3.0 PackageVersion: v0.3.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: e6ac66ef043540fb1bd849b36ae1582dc360d9a274cbd9cc9768d1659f9e59fa PackageHomePage: https://github.com/Azure/go-autorest/autorest/date PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/Azure/go-autorest/logger PackageName: github.com/Azure/go-autorest/logger SPDXID: SPDXRef-Package-github.com.Azure.go-autorest.logger-v0.2.1 PackageVersion: v0.2.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 6f980aaf27fee26a7f7017d638e0b9092a26c1c7af79b8263bf4a6e2a20452c6 PackageHomePage: https://github.com/Azure/go-autorest/logger PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/Azure/go-autorest/tracing PackageName: github.com/Azure/go-autorest/tracing SPDXID: SPDXRef-Package-github.com.Azure.go-autorest.tracing-v0.6.0 PackageVersion: v0.6.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: e9b2a988aca23d841384a17068de9dcd59ccb7032cd6eadf05430edd426134c2 PackageHomePage: https://github.com/Azure/go-autorest/tracing PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/form3tech-oss/jwt-go PackageName: github.com/form3tech-oss/jwt-go SPDXID: SPDXRef-Package-github.com.form3tech-oss.jwt-go-v3.2.2+incompatible PackageVersion: v3.2.2+incompatible PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 4a559f8950d5014570c484552049fa65e1c9eaa3ee5aac02920020103d345f9c PackageHomePage: https://github.com/form3tech-oss/jwt-go PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/Azure/go-autorest/autorest/adal PackageName: github.com/Azure/go-autorest/autorest/adal SPDXID: SPDXRef-Package-github.com.Azure.go-autorest.autorest.adal-v0.9.13 PackageVersion: v0.9.13 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 1d8888e699a769d032389aa3de1f49bbdda2bf7c250baf1376146ec54228851b PackageHomePage: https://github.com/Azure/go-autorest/autorest/adal PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.Azure.go-autorest.autorest.adal-v0.9.13 DEPENDS_ON SPDXRef-Package-github.com.Azure.go-autorest.autorest.date-v0.3.0 Relationship SPDXRef-Package-github.com.Azure.go-autorest.autorest.adal-v0.9.13 DEPENDS_ON SPDXRef-Package-github.com.Azure.go-autorest.tracing-v0.6.0 Relationship SPDXRef-Package-github.com.Azure.go-autorest.autorest.adal-v0.9.13 DEPENDS_ON SPDXRef-Package-github.com.form3tech-oss.jwt-go-v3.2.2+incompatible Relationship SPDXRef-Package-github.com.Azure.go-autorest.autorest.adal-v0.9.13 DEPENDS_ON SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e Relationship SPDXRef-Package-github.com.Azure.go-autorest.autorest.adal-v0.9.13 DEPENDS_ON SPDXRef-Package-github.com.Azure.go-autorest.logger-v0.2.1 ##### Package representing the github.com/Azure/go-autorest/autorest PackageName: github.com/Azure/go-autorest/autorest SPDXID: SPDXRef-Package-github.com.Azure.go-autorest.autorest-v0.11.18 PackageVersion: v0.11.18 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 7b85debcce807a016fbdae358971274f74c396ab20b58a73e8fa69fcaed58912 PackageHomePage: https://github.com/Azure/go-autorest/autorest PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.Azure.go-autorest.autorest-v0.11.18 DEPENDS_ON SPDXRef-Package-github.com.Azure.go-autorest.autorest.adal-v0.9.13 Relationship SPDXRef-Package-github.com.Azure.go-autorest.autorest-v0.11.18 DEPENDS_ON SPDXRef-Package-github.com.Azure.go-autorest.logger-v0.2.1 Relationship SPDXRef-Package-github.com.Azure.go-autorest.autorest-v0.11.18 DEPENDS_ON SPDXRef-Package-github.com.Azure.go-autorest.tracing-v0.6.0 Relationship SPDXRef-Package-github.com.Azure.go-autorest.autorest-v0.11.18 DEPENDS_ON SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e ##### Package representing the github.com/imdario/mergo PackageName: github.com/imdario/mergo SPDXID: SPDXRef-Package-github.com.imdario.mergo-v0.3.9 PackageVersion: v0.3.9 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 0ee96fdd2abc1d04b65d2bc2fcc2de4ae71b231e9543893db38016cd6822ae5c PackageHomePage: https://github.com/imdario/mergo PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/OneOfOne/xxhash PackageName: github.com/OneOfOne/xxhash SPDXID: SPDXRef-Package-github.com.OneOfOne.xxhash-v1.2.8 PackageVersion: v1.2.8 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 72ca3234e0a2f98565da9eef27df8a5a3f8652e74066cd454feba34fe160787e PackageHomePage: https://github.com/OneOfOne/xxhash PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/open-policy-agent/opa PackageName: github.com/open-policy-agent/opa SPDXID: SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 PackageVersion: v0.29.4 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: d45f3fe23dd8e18a1bd1ef0aa85ab059ed17d7a27bfd3d060d0c625186729110 PackageHomePage: https://github.com/open-policy-agent/opa PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-github.com.yashtewari.glob-intersection-v0.0.0-20180916065949-5c77d914dd0b Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-github.com.xeipuuv.gojsonreference-v0.0.0-20180127040603-bd5ef7bd5415 Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-github.com.spf13.cobra-v1.1.3 Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-github.com.peterh.liner-v0.0.0-20170211195444-bf27d3ba8e1d Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-github.com.gorilla.mux-v1.8.0 Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-golang.org.x.time-v0.0.0-20210220033141-f8bda1e9f3ba Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-github.com.prometheus.common-v0.29.0 Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-github.com.olekukonko.tablewriter-v0.0.5 Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-github.com.fsnotify.fsnotify-v1.4.9 Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-github.com.xeipuuv.gojsonpointer-v0.0.0-20190905194746-02993c407bfb Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-github.com.pkg.errors-v0.9.1 Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-github.com.golang.protobuf-v1.5.2 Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-github.com.gobwas.glob-v0.2.3 Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-github.com.prometheus.procfs-v0.6.0 Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-go.uber.org.automaxprocs-v1.4.0 Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-github.com.spf13.pflag-v1.0.5 Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-github.com.sirupsen.logrus-v1.8.1 Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-github.com.rcrowley.go-metrics-v0.0.0-20200313005456-10cdbea86bc0 Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-github.com.ghodss.yaml-v1.0.0 Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-github.com.OneOfOne.xxhash-v1.2.8 Relationship SPDXRef-Package-github.com.open-policy-agent.opa-v0.29.4 DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 ##### Package representing the github.com/xeipuuv/gojsonpointer PackageName: github.com/xeipuuv/gojsonpointer SPDXID: SPDXRef-Package-github.com.xeipuuv.gojsonpointer-v0.0.0-20190905194746-02993c407bfb PackageVersion: v0.0.0-20190905194746-02993c407bfb PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 63a2e8a1e3a190e1bc3280e3940d846c646ef3e908736ae72db9076029fcc706 PackageHomePage: https://github.com/xeipuuv/gojsonpointer PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/xeipuuv/gojsonreference PackageName: github.com/xeipuuv/gojsonreference SPDXID: SPDXRef-Package-github.com.xeipuuv.gojsonreference-v0.0.0-20180127040603-bd5ef7bd5415 PackageVersion: v0.0.0-20180127040603-bd5ef7bd5415 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 0200ca87486b0155e8c199eec9323c321665bb4938eccbac72d8547ed2082d6b PackageHomePage: https://github.com/xeipuuv/gojsonreference PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/rcrowley/go-metrics PackageName: github.com/rcrowley/go-metrics SPDXID: SPDXRef-Package-github.com.rcrowley.go-metrics-v0.0.0-20200313005456-10cdbea86bc0 PackageVersion: v0.0.0-20200313005456-10cdbea86bc0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: bd748d8975427958e55da8adae7bcbe43186d696e49a4804df848d113506ca45 PackageHomePage: https://github.com/rcrowley/go-metrics PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/mattn/go-runewidth PackageName: github.com/mattn/go-runewidth SPDXID: SPDXRef-Package-github.com.mattn.go-runewidth-v0.0.9 PackageVersion: v0.0.9 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: c0e249b2e49600457b866fa58f7075c833cd697601317bc0d8814817a4546987 PackageHomePage: https://github.com/mattn/go-runewidth PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/olekukonko/tablewriter PackageName: github.com/olekukonko/tablewriter SPDXID: SPDXRef-Package-github.com.olekukonko.tablewriter-v0.0.5 PackageVersion: v0.0.5 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 9e2c85817b12fce5ea554bb854c62ce8c10ae5124532ea9c3abee1c8d76f4105 PackageHomePage: https://github.com/olekukonko/tablewriter PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.olekukonko.tablewriter-v0.0.5 DEPENDS_ON SPDXRef-Package-github.com.mattn.go-runewidth-v0.0.9 Relationship SPDXRef-Package-github.com.olekukonko.tablewriter-v0.0.5 DEPENDS_ON SPDXRef-Package-github.com.olekukonko.tablewriter-v0.0.5 ##### Package representing the github.com/gobwas/glob PackageName: github.com/gobwas/glob SPDXID: SPDXRef-Package-github.com.gobwas.glob-v0.2.3 PackageVersion: v0.2.3 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 15b4a39767c64f15c6f6bc35d96f85768413a25bdfa4e46fa49a6374c9b7968b PackageHomePage: https://github.com/gobwas/glob PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/yashtewari/glob-intersection PackageName: github.com/yashtewari/glob-intersection SPDXID: SPDXRef-Package-github.com.yashtewari.glob-intersection-v0.0.0-20180916065949-5c77d914dd0b PackageVersion: v0.0.0-20180916065949-5c77d914dd0b PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 4ff4c9ffae6f6732584eb088757d9fcb30d0dc960c5b4e00c0cd4e05bacc04e4 PackageHomePage: https://github.com/yashtewari/glob-intersection PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/sirupsen/logrus PackageName: github.com/sirupsen/logrus SPDXID: SPDXRef-Package-github.com.sirupsen.logrus-v1.8.1 PackageVersion: v1.8.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: adea913fb1c1be8bf12e8b69d1da7f226c014c55caf8e56335bbe4e114e41b50 PackageHomePage: https://github.com/sirupsen/logrus PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.sirupsen.logrus-v1.8.1 DEPENDS_ON SPDXRef-Package-github.com.davecgh.go-spew-v1.1.1 Relationship SPDXRef-Package-github.com.sirupsen.logrus-v1.8.1 DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 Relationship SPDXRef-Package-github.com.sirupsen.logrus-v1.8.1 DEPENDS_ON SPDXRef-Package-golang.org.x.crypto-v0.0.0-20210616213533-5ff15b29337e ##### Package representing the github.com/gorilla/mux PackageName: github.com/gorilla/mux SPDXID: SPDXRef-Package-github.com.gorilla.mux-v1.8.0 PackageVersion: v1.8.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 2dffd95dd340d7e6948873a146da12fd4146c08eb6eb8c420f76e8d9a742814c PackageHomePage: https://github.com/gorilla/mux PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/beorn7/perks PackageName: github.com/beorn7/perks SPDXID: SPDXRef-Package-github.com.beorn7.perks-v1.0.1 PackageVersion: v1.0.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 3f909457dc97a398f2d35bf26e5a7ba7af74a4b47f83b79dea360415ed24a98e PackageHomePage: https://github.com/beorn7/perks PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/cespare/xxhash/v2 PackageName: github.com/cespare/xxhash/v2 SPDXID: SPDXRef-Package-github.com.cespare.xxhash.v2-v2.1.1 PackageVersion: v2.1.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 7d5ac3d632362d4e19965eb9745b4092e9e62bd9bccde15d4975cc5a97649c63 PackageHomePage: https://github.com/cespare/xxhash/v2 PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/prometheus/client_model PackageName: github.com/prometheus/client_model SPDXID: SPDXRef-Package-github.com.prometheus.client-model-v0.2.0 PackageVersion: v0.2.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 4cc56642e11499313e9e0c16d30a8ba751e2f9c591dc6a1e7d675cf0e09e03d0 PackageHomePage: https://github.com/prometheus/client_model PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.prometheus.client-model-v0.2.0 DEPENDS_ON SPDXRef-Package-golang.org.x.sync-v0.0.0-20210220032951-036812b2e83c Relationship SPDXRef-Package-github.com.prometheus.client-model-v0.2.0 DEPENDS_ON SPDXRef-Package-github.com.golang.protobuf-v1.5.2 ##### Package representing the github.com/prometheus/client_golang PackageName: github.com/prometheus/client_golang SPDXID: SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 PackageVersion: v1.11.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: ed14dd907bac61d8ae65bcb0211771c661e1cf1f7fd2b1394b9b124893705177 PackageHomePage: https://github.com/prometheus/client_golang PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 DEPENDS_ON SPDXRef-Package-github.com.beorn7.perks-v1.0.1 Relationship SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 Relationship SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 DEPENDS_ON SPDXRef-Package-github.com.modern-go.reflect2-v1.0.1 Relationship SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 DEPENDS_ON SPDXRef-Package-github.com.matttproud.golang-protobuf-extensions-v1.0.1 Relationship SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 DEPENDS_ON SPDXRef-Package-github.com.json-iterator.go-v1.1.11 Relationship SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 DEPENDS_ON SPDXRef-Package-github.com.prometheus.common-v0.29.0 Relationship SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 DEPENDS_ON SPDXRef-Package-github.com.google.go-cmp-v0.5.6 Relationship SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 DEPENDS_ON SPDXRef-Package-github.com.modern-go.concurrent-v0.0.0-20180306012644-bacd9c7ef1dd Relationship SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 DEPENDS_ON SPDXRef-Package-github.com.prometheus.client-model-v0.2.0 Relationship SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 DEPENDS_ON SPDXRef-Package-github.com.prometheus.procfs-v0.6.0 Relationship SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 DEPENDS_ON SPDXRef-Package-golang.org.x.text-v0.3.6 Relationship SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 DEPENDS_ON SPDXRef-Package-google.golang.org.protobuf-v1.26.0 Relationship SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 DEPENDS_ON SPDXRef-Package-golang.org.x.sync-v0.0.0-20210220032951-036812b2e83c Relationship SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 DEPENDS_ON SPDXRef-Package-github.com.cespare.xxhash.v2-v2.1.1 Relationship SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 DEPENDS_ON SPDXRef-Package-github.com.golang.protobuf-v1.5.2 Relationship SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 ##### Package representing the github.com/matttproud/golang_protobuf_extensions PackageName: github.com/matttproud/golang_protobuf_extensions SPDXID: SPDXRef-Package-github.com.matttproud.golang-protobuf-extensions-v1.0.1 PackageVersion: v1.0.1 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: d8a0ce3a4b0ec610a7ee215ad6b63ee7f83fa14f7ecea46ad86dad3f8f3b99e7 PackageHomePage: https://github.com/matttproud/golang_protobuf_extensions PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the github.com/prometheus/common PackageName: github.com/prometheus/common SPDXID: SPDXRef-Package-github.com.prometheus.common-v0.29.0 PackageVersion: v0.29.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: dab655f661cec4b716fb97640b5c38306ce26552865eeacab4a3bc73d43966e7 PackageHomePage: https://github.com/prometheus/common PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.prometheus.common-v0.29.0 DEPENDS_ON SPDXRef-Package-github.com.gogo.protobuf-v1.3.2 Relationship SPDXRef-Package-github.com.prometheus.common-v0.29.0 DEPENDS_ON SPDXRef-Package-github.com.prometheus.procfs-v0.6.0 Relationship SPDXRef-Package-github.com.prometheus.common-v0.29.0 DEPENDS_ON SPDXRef-Package-github.com.matttproud.golang-protobuf-extensions-v1.0.1 Relationship SPDXRef-Package-github.com.prometheus.common-v0.29.0 DEPENDS_ON SPDXRef-Package-github.com.prometheus.client-golang-v1.11.0 Relationship SPDXRef-Package-github.com.prometheus.common-v0.29.0 DEPENDS_ON SPDXRef-Package-github.com.prometheus.client-model-v0.2.0 Relationship SPDXRef-Package-github.com.prometheus.common-v0.29.0 DEPENDS_ON SPDXRef-Package-golang.org.x.net-v0.0.0-20210525063256-abc453219eb5 Relationship SPDXRef-Package-github.com.prometheus.common-v0.29.0 DEPENDS_ON SPDXRef-Package-github.com.beorn7.perks-v1.0.1 Relationship SPDXRef-Package-github.com.prometheus.common-v0.29.0 DEPENDS_ON SPDXRef-Package-github.com.go-stack.stack-v1.8.0 Relationship SPDXRef-Package-github.com.prometheus.common-v0.29.0 DEPENDS_ON SPDXRef-Package-github.com.golang.protobuf-v1.5.2 Relationship SPDXRef-Package-github.com.prometheus.common-v0.29.0 DEPENDS_ON SPDXRef-Package-github.com.sirupsen.logrus-v1.8.1 Relationship SPDXRef-Package-github.com.prometheus.common-v0.29.0 DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 Relationship SPDXRef-Package-github.com.prometheus.common-v0.29.0 DEPENDS_ON SPDXRef-Package-gopkg.in.yaml.v2-v2.4.0 Relationship SPDXRef-Package-github.com.prometheus.common-v0.29.0 DEPENDS_ON SPDXRef-Package-golang.org.x.oauth2-v0.0.0-20210514164344-f6687ab2804c Relationship SPDXRef-Package-github.com.prometheus.common-v0.29.0 DEPENDS_ON SPDXRef-Package-github.com.pkg.errors-v0.9.1 Relationship SPDXRef-Package-github.com.prometheus.common-v0.29.0 DEPENDS_ON SPDXRef-Package-golang.org.x.sync-v0.0.0-20210220032951-036812b2e83c ##### Package representing the github.com/prometheus/procfs PackageName: github.com/prometheus/procfs SPDXID: SPDXRef-Package-github.com.prometheus.procfs-v0.6.0 PackageVersion: v0.6.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 86bd64823e49f5c1bedae11007fb801c88d3b28ac5e712d4002355a3101a2ddd PackageHomePage: https://github.com/prometheus/procfs PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION Relationship SPDXRef-Package-github.com.prometheus.procfs-v0.6.0 DEPENDS_ON SPDXRef-Package-github.com.google.go-cmp-v0.5.6 Relationship SPDXRef-Package-github.com.prometheus.procfs-v0.6.0 DEPENDS_ON SPDXRef-Package-golang.org.x.sync-v0.0.0-20210220032951-036812b2e83c Relationship SPDXRef-Package-github.com.prometheus.procfs-v0.6.0 DEPENDS_ON SPDXRef-Package-golang.org.x.sys-v0.0.0-20210615035016-665e8c7367d1 ##### Package representing the github.com/peterh/liner PackageName: github.com/peterh/liner SPDXID: SPDXRef-Package-github.com.peterh.liner-v0.0.0-20170211195444-bf27d3ba8e1d PackageVersion: v0.0.0-20170211195444-bf27d3ba8e1d PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 246b8db15eff422e821053ea3d13e8d076779b5c62fcdbefdd1f18b71235b67f PackageHomePage: https://github.com/peterh/liner PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ##### Package representing the go.uber.org/automaxprocs PackageName: go.uber.org/automaxprocs SPDXID: SPDXRef-Package-go.uber.org.automaxprocs-v1.4.0 PackageVersion: v1.4.0 PackageSupplier: NOASSERTION PackageDownloadLocation: NOASSERTION FilesAnalyzed: false PackageChecksum: SHA256: 32be51bf668d3280000ab7aa1f970025fb49ef841201405a37d4cc98aaf7c71f PackageHomePage: https://go.uber.org/automaxprocs PackageLicenseConcluded: NOASSERTION PackageLicenseDeclared: NOASSERTION PackageCopyrightText: NOASSERTION PackageLicenseComments: NOASSERTION PackageComment: NOASSERTION ================================================ FILE: test/testdata/fancy_from.Dockerfile ================================================ # Copyright 2021 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. FROM --platform=linux/amd64 ghcr.io/chainguard-images/alpine-base AS base # blah blah ================================================ FILE: test/testdata/policies/cue-fails.cue ================================================ import "time" before: time.Parse(time.RFC3339, "2049-10-09T17:10:27Z") // Test with invalid predicate type. It should be this, so change it //predicateType: "cosign.sigstore.dev/attestation/v1" predicateType: "cosignnotreally.sigstore.dev/attestation/v1" // The predicate must match the following constraints. predicate: { Timestamp: after scanFinishedOn: after } } ================================================ FILE: test/testdata/policies/cue-vuln-works.cue ================================================ import "time" before: time.Parse(time.RFC3339, "2022-04-15T17:10:27Z") after: time.Parse(time.RFC3339, "2022-03-09T17:10:27Z") // The predicateType field must match this string predicateType: "https://cosign.sigstore.dev/attestation/vuln/v1" predicate: { invocation: { uri: "invocation.example.com/cosign-testing" } scanner: { uri: "fakescanner.example.com/cosign-testing" } metadata: { scanStartedOn: after scanFinishedOn: after } } ================================================ FILE: test/testdata/policies/cue-works.cue ================================================ import "time" before: time.Parse(time.RFC3339, "2049-10-09T17:10:27Z") // The predicateType field must match this string predicateType: "https://cosign.sigstore.dev/attestation/v1" // The predicate must match the following constraints. predicate: { Timestamp: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/blang/semver/v4/LICENSE ================================================ The MIT License Copyright (c) 2014 Benedikt Lang Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/blendle/zapdriver/LICENSE ================================================ ISC License Copyright (c) Blendle Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/cenkalti/backoff/v4/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 Cenk Altı Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/cenkalti/backoff/v5/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 Cenk Altı Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/census-instrumentation/opencensus-proto/gen-go/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/cespare/xxhash/v2/LICENSE.txt ================================================ Copyright (c) 2016 Caleb Spare MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/chrismellard/docker-credential-acr-env/pkg/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/clbanning/mxj/v2/LICENSE ================================================ Copyright (c) 2012-2021 Charles Banning . All rights reserved. The MIT License (MIT) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/cockroachdb/apd/v3/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {} 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/common-nighthawk/go-figure/LICENSE ================================================ MIT License Copyright (c) 2018 Daniel Deutsch Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/containerd/errdefs/LICENSE ================================================ Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS Copyright The containerd 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 https://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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/containerd/errdefs/pkg/LICENSE ================================================ Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS Copyright The containerd 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 https://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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/containerd/stargz-snapshotter/estargz/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/coreos/go-oidc/v3/oidc/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/coreos/go-oidc/v3/oidc/NOTICE ================================================ CoreOS Project Copyright 2014 CoreOS, Inc This product includes software developed at CoreOS, Inc. (http://www.coreos.com/). ================================================ FILE: third_party/VENDOR-LICENSE/github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer/LICENSE ================================================ Copyright 2018 Anders Rundgren 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 https://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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/davecgh/go-spew/spew/LICENSE ================================================ ISC License Copyright (c) 2012-2016 Dave Collins Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/digitorus/pkcs7/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2015 Andrew Smith Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/digitorus/timestamp/LICENSE ================================================ BSD 2-Clause License Copyright (c) 2017, Digitorus B.V. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/dimchansky/utfbom/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright (c) 2018-2020, Dmitrij Koniajev (dimchansky@gmail.com) 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/distribution/reference/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/docker/cli/cli/config/LICENSE ================================================ Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS Copyright 2013-2017 Docker, Inc. 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 https://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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/docker/cli/cli/config/NOTICE ================================================ Docker Copyright 2012-2017 Docker, Inc. This product includes software developed at Docker, Inc. (https://www.docker.com). This product contains software (https://github.com/creack/pty) developed by Keith Rarick, licensed under the MIT License. The following is courtesy of our legal counsel: Use and transfer of Docker may be subject to certain restrictions by the United States and other governments. It is your responsibility to ensure that your use and/or transfer does not violate applicable laws. For more information, see https://www.bis.doc.gov See also https://www.apache.org/dev/crypto.html and/or seek legal counsel. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/docker/distribution/registry/client/auth/challenge/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/docker/docker/LICENSE ================================================ Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS Copyright 2013-2018 Docker, Inc. 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 https://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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/docker/docker/NOTICE ================================================ Docker Copyright 2012-2017 Docker, Inc. This product includes software developed at Docker, Inc. (https://www.docker.com). This product contains software (https://github.com/creack/pty) developed by Keith Rarick, licensed under the MIT License. The following is courtesy of our legal counsel: Use and transfer of Docker may be subject to certain restrictions by the United States and other governments. It is your responsibility to ensure that your use and/or transfer does not violate applicable laws. For more information, please see https://www.bis.doc.gov See also https://www.apache.org/dev/crypto.html and/or seek legal counsel. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/docker/docker-credential-helpers/LICENSE ================================================ Copyright (c) 2016 David Calavera Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/docker/go-connections/LICENSE ================================================ Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS Copyright 2015 Docker, Inc. 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 https://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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/docker/go-units/LICENSE ================================================ Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS Copyright 2015 Docker, Inc. 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 https://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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/dustin/go-humanize/LICENSE ================================================ Copyright (c) 2005-2008 Dustin Sallings Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/emicklei/go-restful/v3/LICENSE ================================================ Copyright (c) 2012,2013 Ernest Micklei MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/emicklei/proto/LICENSE ================================================ Copyright (c) 2017 Ernest Micklei MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/evanphx/json-patch/v5/LICENSE ================================================ Copyright (c) 2014, Evan Phoenix All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Evan Phoenix nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/felixge/httpsnoop/LICENSE.txt ================================================ Copyright (c) 2016 Felix Geisendörfer (felix@debuggable.com) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/fsnotify/fsnotify/LICENSE ================================================ Copyright © 2012 The Go Authors. All rights reserved. Copyright © fsnotify Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/fxamacker/cbor/v2/LICENSE ================================================ MIT License Copyright (c) 2019-present Faye Amacker Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-chi/chi/v5/LICENSE ================================================ Copyright (c) 2015-present Peter Kieltyka (https://github.com/pkieltyka), Google Inc. MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-ini/ini/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2014 Unknwon 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-jose/go-jose/v4/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-jose/go-jose/v4/json/LICENSE ================================================ Copyright (c) 2012 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-kit/log/LICENSE ================================================ MIT License Copyright (c) 2021 Go kit Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-logfmt/logfmt/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2015 go-logfmt Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-logr/logr/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-logr/stdr/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/analysis/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/errors/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/jsonpointer/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/jsonpointer/NOTICE ================================================ Copyright 2015-2025 go-swagger maintainers // SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers // SPDX-License-Identifier: Apache-2.0 This software library, github.com/go-openapi/jsonpointer, includes software developed by the go-swagger and go-openapi maintainers ("go-swagger maintainers"). Licensed under the Apache License, Version 2.0 (the "License"); you may not use this software except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. This software is copied from, derived from, and inspired by other original software products. It ships with copies of other software which license terms are recalled below. The original software was authored on 25-02-2013 by sigu-399 (https://github.com/sigu-399, sigu.399@gmail.com). github.com/sigh-399/jsonpointer =========================== // SPDX-FileCopyrightText: Copyright 2013 sigu-399 ( https://github.com/sigu-399 ) // SPDX-License-Identifier: Apache-2.0 Copyright 2013 sigu-399 ( https://github.com/sigu-399 ) 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/jsonreference/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/jsonreference/NOTICE ================================================ Copyright 2015-2025 go-swagger maintainers // SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers // SPDX-License-Identifier: Apache-2.0 This software library, github.com/go-openapi/jsonpointer, includes software developed by the go-swagger and go-openapi maintainers ("go-swagger maintainers"). Licensed under the Apache License, Version 2.0 (the "License"); you may not use this software except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. This software is copied from, derived from, and inspired by other original software products. It ships with copies of other software which license terms are recalled below. The original software was authored on 25-02-2013 by sigu-399 (https://github.com/sigu-399, sigu.399@gmail.com). github.com/sigh-399/jsonpointer =========================== // SPDX-FileCopyrightText: Copyright 2013 sigu-399 ( https://github.com/sigu-399 ) // SPDX-License-Identifier: Apache-2.0 Copyright 2013 sigu-399 ( https://github.com/sigu-399 ) 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/loads/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/runtime/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/runtime/middleware/denco/LICENSE ================================================ Copyright (c) 2014 Naoya Inada Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/spec/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/strfmt/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/swag/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/swag/cmdutils/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/swag/conv/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/swag/fileutils/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/swag/jsonname/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/swag/jsonutils/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/swag/loading/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/swag/mangling/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/swag/netutils/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/swag/stringutils/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/swag/typeutils/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/swag/yamlutils/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-openapi/validate/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/go-viper/mapstructure/v2/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2013 Mitchell Hashimoto Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/gobuffalo/flect/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2019 Mark Bates Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/gobwas/glob/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2016 Sergey Kamardin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/gogo/protobuf/LICENSE ================================================ Copyright (c) 2013, The GoGo Authors. All rights reserved. Protocol Buffers for Go with Gadgets Go support for Protocol Buffers - Google's data interchange format Copyright 2010 The Go Authors. All rights reserved. https://github.com/golang/protobuf Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/golang/groupcache/lru/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/golang/protobuf/ptypes/timestamp/LICENSE ================================================ Copyright 2010 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/golang/snappy/LICENSE ================================================ Copyright (c) 2011 The Snappy-Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/golang-jwt/jwt/v4/LICENSE ================================================ Copyright (c) 2012 Dave Grijalva Copyright (c) 2021 golang-jwt maintainers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/golang-jwt/jwt/v5/LICENSE ================================================ Copyright (c) 2012 Dave Grijalva Copyright (c) 2021 golang-jwt maintainers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/google/certificate-transparency-go/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/google/gnostic-models/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/google/go-cmp/cmp/LICENSE ================================================ Copyright (c) 2017 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/google/go-containerregistry/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/google/go-containerregistry/pkg/authn/k8schain/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/google/go-containerregistry/pkg/authn/kubernetes/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/google/go-github/v73/github/LICENSE ================================================ Copyright (c) 2013 The go-github AUTHORS. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/google/go-querystring/query/LICENSE ================================================ Copyright (c) 2013 Google. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/google/s2a-go/LICENSE.md ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/google/uuid/LICENSE ================================================ Copyright (c) 2009,2014 Google Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/googleapis/enterprise-certificate-proxy/client/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/googleapis/gax-go/v2/LICENSE ================================================ Copyright 2016, Google Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/grpc-ecosystem/grpc-gateway/v2/LICENSE ================================================ Copyright (c) 2015, Gengo, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Gengo, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/errwrap/LICENSE ================================================ Mozilla Public License, version 2.0 1. Definitions 1.1. “Contributor” means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. “Contributor Version” means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor’s Contribution. 1.3. “Contribution” means Covered Software of a particular Contributor. 1.4. “Covered Software” means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. “Incompatible With Secondary Licenses” means a. that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or b. that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. “Executable Form” means any form of the work other than Source Code Form. 1.7. “Larger Work” means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. “License” means this document. 1.9. “Licensable” means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. “Modifications” means any of the following: a. any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or b. any new file in Source Code Form that contains any Covered Software. 1.11. “Patent Claims” of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. “Secondary License” means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. “Source Code Form” means the form of the work preferred for making modifications. 1.14. “You” (or “Your”) means an individual or a legal entity exercising rights under this License. For legal entities, “You” includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, “control” means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: a. under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and b. under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: a. for any code that a Contributor has removed from Covered Software; or b. for infringements caused by: (i) Your and any other third party’s modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or c. under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients’ rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: a. such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and b. You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients’ rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. 6. Disclaimer of Warranty Covered Software is provided under this License on an “as is” basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer. 7. Limitation of Liability Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party’s negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You. 8. Litigation Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party’s ability to bring cross-claims or counter-claims. 9. Miscellaneous This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - “Incompatible With Secondary Licenses” Notice This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/errwrap/README.md ================================================ # errwrap `errwrap` is a package for Go that formalizes the pattern of wrapping errors and checking if an error contains another error. There is a common pattern in Go of taking a returned `error` value and then wrapping it (such as with `fmt.Errorf`) before returning it. The problem with this pattern is that you completely lose the original `error` structure. Arguably the _correct_ approach is that you should make a custom structure implementing the `error` interface, and have the original error as a field on that structure, such [as this example](http://golang.org/pkg/os/#PathError). This is a good approach, but you have to know the entire chain of possible rewrapping that happens, when you might just care about one. `errwrap` formalizes this pattern (it doesn't matter what approach you use above) by giving a single interface for wrapping errors, checking if a specific error is wrapped, and extracting that error. ## Installation and Docs Install using `go get github.com/hashicorp/errwrap`. Full documentation is available at http://godoc.org/github.com/hashicorp/errwrap ## Usage #### Basic Usage Below is a very basic example of its usage: ```go // A function that always returns an error, but wraps it, like a real // function might. func tryOpen() error { _, err := os.Open("/i/dont/exist") if err != nil { return errwrap.Wrapf("Doesn't exist: {{err}}", err) } return nil } func main() { err := tryOpen() // We can use the Contains helpers to check if an error contains // another error. It is safe to do this with a nil error, or with // an error that doesn't even use the errwrap package. if errwrap.Contains(err, "does not exist") { // Do something } if errwrap.ContainsType(err, new(os.PathError)) { // Do something } // Or we can use the associated `Get` functions to just extract // a specific error. This would return nil if that specific error doesn't // exist. perr := errwrap.GetType(err, new(os.PathError)) } ``` #### Custom Types If you're already making custom types that properly wrap errors, then you can get all the functionality of `errwraps.Contains` and such by implementing the `Wrapper` interface with just one function. Example: ```go type AppError { Code ErrorCode Err error } func (e *AppError) WrappedErrors() []error { return []error{e.Err} } ``` Now this works: ```go err := &AppError{Err: fmt.Errorf("an error")} if errwrap.ContainsType(err, fmt.Errorf("")) { // This will work! } ``` ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/errwrap/errwrap.go ================================================ // Package errwrap implements methods to formalize error wrapping in Go. // // All of the top-level functions that take an `error` are built to be able // to take any error, not just wrapped errors. This allows you to use errwrap // without having to type-check and type-cast everywhere. package errwrap import ( "errors" "reflect" "strings" ) // WalkFunc is the callback called for Walk. type WalkFunc func(error) // Wrapper is an interface that can be implemented by custom types to // have all the Contains, Get, etc. functions in errwrap work. // // When Walk reaches a Wrapper, it will call the callback for every // wrapped error in addition to the wrapper itself. Since all the top-level // functions in errwrap use Walk, this means that all those functions work // with your custom type. type Wrapper interface { WrappedErrors() []error } // Wrap defines that outer wraps inner, returning an error type that // can be cleanly used with the other methods in this package, such as // Contains, GetAll, etc. // // This function won't modify the error message at all (the outer message // will be used). func Wrap(outer, inner error) error { return &wrappedError{ Outer: outer, Inner: inner, } } // Wrapf wraps an error with a formatting message. This is similar to using // `fmt.Errorf` to wrap an error. If you're using `fmt.Errorf` to wrap // errors, you should replace it with this. // // format is the format of the error message. The string '{{err}}' will // be replaced with the original error message. // // Deprecated: Use fmt.Errorf() func Wrapf(format string, err error) error { outerMsg := "" if err != nil { outerMsg = err.Error() } outer := errors.New(strings.Replace( format, "{{err}}", outerMsg, -1)) return Wrap(outer, err) } // Contains checks if the given error contains an error with the // message msg. If err is not a wrapped error, this will always return // false unless the error itself happens to match this msg. func Contains(err error, msg string) bool { return len(GetAll(err, msg)) > 0 } // ContainsType checks if the given error contains an error with // the same concrete type as v. If err is not a wrapped error, this will // check the err itself. func ContainsType(err error, v interface{}) bool { return len(GetAllType(err, v)) > 0 } // Get is the same as GetAll but returns the deepest matching error. func Get(err error, msg string) error { es := GetAll(err, msg) if len(es) > 0 { return es[len(es)-1] } return nil } // GetType is the same as GetAllType but returns the deepest matching error. func GetType(err error, v interface{}) error { es := GetAllType(err, v) if len(es) > 0 { return es[len(es)-1] } return nil } // GetAll gets all the errors that might be wrapped in err with the // given message. The order of the errors is such that the outermost // matching error (the most recent wrap) is index zero, and so on. func GetAll(err error, msg string) []error { var result []error Walk(err, func(err error) { if err.Error() == msg { result = append(result, err) } }) return result } // GetAllType gets all the errors that are the same type as v. // // The order of the return value is the same as described in GetAll. func GetAllType(err error, v interface{}) []error { var result []error var search string if v != nil { search = reflect.TypeOf(v).String() } Walk(err, func(err error) { var needle string if err != nil { needle = reflect.TypeOf(err).String() } if needle == search { result = append(result, err) } }) return result } // Walk walks all the wrapped errors in err and calls the callback. If // err isn't a wrapped error, this will be called once for err. If err // is a wrapped error, the callback will be called for both the wrapper // that implements error as well as the wrapped error itself. func Walk(err error, cb WalkFunc) { if err == nil { return } switch e := err.(type) { case *wrappedError: cb(e.Outer) Walk(e.Inner, cb) case Wrapper: cb(err) for _, err := range e.WrappedErrors() { Walk(err, cb) } case interface{ Unwrap() error }: cb(err) Walk(e.Unwrap(), cb) default: cb(err) } } // wrappedError is an implementation of error that has both the // outer and inner errors. type wrappedError struct { Outer error Inner error } func (w *wrappedError) Error() string { return w.Outer.Error() } func (w *wrappedError) WrappedErrors() []error { return []error{w.Outer, w.Inner} } func (w *wrappedError) Unwrap() error { return w.Inner } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-cleanhttp/LICENSE ================================================ Mozilla Public License, version 2.0 1. Definitions 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means a. that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or b. that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: a. any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or b. any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: a. under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and b. under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: a. for any code that a Contributor has removed from Covered Software; or b. for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or c. under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: a. such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and b. You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. 6. Disclaimer of Warranty Covered Software is provided under this License on an "as is" basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer. 7. Limitation of Liability Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party's negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You. 8. Litigation Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-cleanhttp/README.md ================================================ # cleanhttp Functions for accessing "clean" Go http.Client values ------------- The Go standard library contains a default `http.Client` called `http.DefaultClient`. It is a common idiom in Go code to start with `http.DefaultClient` and tweak it as necessary, and in fact, this is encouraged; from the `http` package documentation: > The Client's Transport typically has internal state (cached TCP connections), so Clients should be reused instead of created as needed. Clients are safe for concurrent use by multiple goroutines. Unfortunately, this is a shared value, and it is not uncommon for libraries to assume that they are free to modify it at will. With enough dependencies, it can be very easy to encounter strange problems and race conditions due to manipulation of this shared value across libraries and goroutines (clients are safe for concurrent use, but writing values to the client struct itself is not protected). Making things worse is the fact that a bare `http.Client` will use a default `http.Transport` called `http.DefaultTransport`, which is another global value that behaves the same way. So it is not simply enough to replace `http.DefaultClient` with `&http.Client{}`. This repository provides some simple functions to get a "clean" `http.Client` -- one that uses the same default values as the Go standard library, but returns a client that does not share any state with other clients. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-cleanhttp/cleanhttp.go ================================================ package cleanhttp import ( "net" "net/http" "runtime" "time" ) // DefaultTransport returns a new http.Transport with similar default values to // http.DefaultTransport, but with idle connections and keepalives disabled. func DefaultTransport() *http.Transport { transport := DefaultPooledTransport() transport.DisableKeepAlives = true transport.MaxIdleConnsPerHost = -1 return transport } // DefaultPooledTransport returns a new http.Transport with similar default // values to http.DefaultTransport. Do not use this for transient transports as // it can leak file descriptors over time. Only use this for transports that // will be re-used for the same host(s). func DefaultPooledTransport() *http.Transport { transport := &http.Transport{ Proxy: http.ProxyFromEnvironment, DialContext: (&net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, DualStack: true, }).DialContext, MaxIdleConns: 100, IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, ForceAttemptHTTP2: true, MaxIdleConnsPerHost: runtime.GOMAXPROCS(0) + 1, } return transport } // DefaultClient returns a new http.Client with similar default values to // http.Client, but with a non-shared Transport, idle connections disabled, and // keepalives disabled. func DefaultClient() *http.Client { return &http.Client{ Transport: DefaultTransport(), } } // DefaultPooledClient returns a new http.Client with similar default values to // http.Client, but with a shared Transport. Do not use this function for // transient clients as it can leak file descriptors over time. Only use this // for clients that will be re-used for the same host(s). func DefaultPooledClient() *http.Client { return &http.Client{ Transport: DefaultPooledTransport(), } } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-cleanhttp/doc.go ================================================ // Package cleanhttp offers convenience utilities for acquiring "clean" // http.Transport and http.Client structs. // // Values set on http.DefaultClient and http.DefaultTransport affect all // callers. This can have detrimental effects, esepcially in TLS contexts, // where client or root certificates set to talk to multiple endpoints can end // up displacing each other, leading to hard-to-debug issues. This package // provides non-shared http.Client and http.Transport structs to ensure that // the configuration will not be overwritten by other parts of the application // or dependencies. // // The DefaultClient and DefaultTransport functions disable idle connections // and keepalives. Without ensuring that idle connections are closed before // garbage collection, short-term clients/transports can leak file descriptors, // eventually leading to "too many open files" errors. If you will be // 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 ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-cleanhttp/handlers.go ================================================ package cleanhttp import ( "net/http" "strings" "unicode" ) // HandlerInput provides input options to cleanhttp's handlers type HandlerInput struct { ErrStatus int } // PrintablePathCheckHandler is a middleware that ensures the request path // contains only printable runes. func PrintablePathCheckHandler(next http.Handler, input *HandlerInput) http.Handler { // Nil-check on input to make it optional if input == nil { input = &HandlerInput{ ErrStatus: http.StatusBadRequest, } } // Default to http.StatusBadRequest on error if input.ErrStatus == 0 { input.ErrStatus = http.StatusBadRequest } return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r != nil { // Check URL path for non-printable characters idx := strings.IndexFunc(r.URL.Path, func(c rune) bool { return !unicode.IsPrint(c) }) if idx != -1 { w.WriteHeader(input.ErrStatus) return } if next != nil { next.ServeHTTP(w, r) } } return }) } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-multierror/LICENSE ================================================ Mozilla Public License, version 2.0 1. Definitions 1.1. “Contributor” means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. “Contributor Version” means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor’s Contribution. 1.3. “Contribution” means Covered Software of a particular Contributor. 1.4. “Covered Software” means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. “Incompatible With Secondary Licenses” means a. that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or b. that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. “Executable Form” means any form of the work other than Source Code Form. 1.7. “Larger Work” means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. “License” means this document. 1.9. “Licensable” means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. “Modifications” means any of the following: a. any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or b. any new file in Source Code Form that contains any Covered Software. 1.11. “Patent Claims” of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. “Secondary License” means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. “Source Code Form” means the form of the work preferred for making modifications. 1.14. “You” (or “Your”) means an individual or a legal entity exercising rights under this License. For legal entities, “You” includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, “control” means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: a. under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and b. under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: a. for any code that a Contributor has removed from Covered Software; or b. for infringements caused by: (i) Your and any other third party’s modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or c. under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients’ rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: a. such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and b. You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients’ rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. 6. Disclaimer of Warranty Covered Software is provided under this License on an “as is” basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer. 7. Limitation of Liability Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party’s negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You. 8. Litigation Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party’s ability to bring cross-claims or counter-claims. 9. Miscellaneous This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - “Incompatible With Secondary Licenses” Notice This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-multierror/Makefile ================================================ TEST?=./... default: test # test runs the test suite and vets the code. test: generate @echo "==> Running tests..." @go list $(TEST) \ | grep -v "/vendor/" \ | xargs -n1 go test -timeout=60s -parallel=10 ${TESTARGS} # testrace runs the race checker testrace: generate @echo "==> Running tests (race)..." @go list $(TEST) \ | grep -v "/vendor/" \ | xargs -n1 go test -timeout=60s -race ${TESTARGS} # updatedeps installs all the dependencies needed to run and build. updatedeps: @sh -c "'${CURDIR}/scripts/deps.sh' '${NAME}'" # generate runs `go generate` to build the dynamically generated source files. generate: @echo "==> Generating..." @find . -type f -name '.DS_Store' -delete @go list ./... \ | grep -v "/vendor/" \ | xargs -n1 go generate .PHONY: default test testrace updatedeps generate ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-multierror/README.md ================================================ # go-multierror [![CircleCI](https://img.shields.io/circleci/build/github/hashicorp/go-multierror/master)](https://circleci.com/gh/hashicorp/go-multierror) [![Go Reference](https://pkg.go.dev/badge/github.com/hashicorp/go-multierror.svg)](https://pkg.go.dev/github.com/hashicorp/go-multierror) ![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/hashicorp/go-multierror) [circleci]: https://app.circleci.com/pipelines/github/hashicorp/go-multierror [godocs]: https://pkg.go.dev/github.com/hashicorp/go-multierror `go-multierror` is a package for Go that provides a mechanism for representing a list of `error` values as a single `error`. This allows a function in Go to return an `error` that might actually be a list of errors. If the caller knows this, they can unwrap the list and access the errors. If the caller doesn't know, the error formats to a nice human-readable format. `go-multierror` is fully compatible with the Go standard library [errors](https://golang.org/pkg/errors/) package, including the functions `As`, `Is`, and `Unwrap`. This provides a standardized approach for introspecting on error values. ## Installation and Docs Install using `go get github.com/hashicorp/go-multierror`. Full documentation is available at https://pkg.go.dev/github.com/hashicorp/go-multierror ### Requires go version 1.13 or newer `go-multierror` requires go version 1.13 or newer. Go 1.13 introduced [error wrapping](https://golang.org/doc/go1.13#error_wrapping), which this library takes advantage of. If you need to use an earlier version of go, you can use the [v1.0.0](https://github.com/hashicorp/go-multierror/tree/v1.0.0) tag, which doesn't rely on features in go 1.13. If you see compile errors that look like the below, it's likely that you're on an older version of go: ``` /go/src/github.com/hashicorp/go-multierror/multierror.go:112:9: undefined: errors.As /go/src/github.com/hashicorp/go-multierror/multierror.go:117:9: undefined: errors.Is ``` ## Usage go-multierror is easy to use and purposely built to be unobtrusive in existing Go applications/libraries that may not be aware of it. **Building a list of errors** The `Append` function is used to create a list of errors. This function behaves a lot like the Go built-in `append` function: it doesn't matter if the first argument is nil, a `multierror.Error`, or any other `error`, the function behaves as you would expect. ```go var result error if err := step1(); err != nil { result = multierror.Append(result, err) } if err := step2(); err != nil { result = multierror.Append(result, err) } return result ``` **Customizing the formatting of the errors** By specifying a custom `ErrorFormat`, you can customize the format of the `Error() string` function: ```go var result *multierror.Error // ... accumulate errors here, maybe using Append if result != nil { result.ErrorFormat = func([]error) string { return "errors!" } } ``` **Accessing the list of errors** `multierror.Error` implements `error` so if the caller doesn't know about multierror, it will work just fine. But if you're aware a multierror might be returned, you can use type switches to access the list of errors: ```go if err := something(); err != nil { if merr, ok := err.(*multierror.Error); ok { // Use merr.Errors } } ``` You can also use the standard [`errors.Unwrap`](https://golang.org/pkg/errors/#Unwrap) function. This will continue to unwrap into subsequent errors until none exist. **Extracting an error** The standard library [`errors.As`](https://golang.org/pkg/errors/#As) function can be used directly with a multierror to extract a specific error: ```go // Assume err is a multierror value err := somefunc() // We want to know if "err" has a "RichErrorType" in it and extract it. var errRich RichErrorType if errors.As(err, &errRich) { // It has it, and now errRich is populated. } ``` **Checking for an exact error value** Some errors are returned as exact errors such as the [`ErrNotExist`](https://golang.org/pkg/os/#pkg-variables) error in the `os` package. You can check if this error is present by using the standard [`errors.Is`](https://golang.org/pkg/errors/#Is) function. ```go // Assume err is a multierror value err := somefunc() if errors.Is(err, os.ErrNotExist) { // err contains os.ErrNotExist } ``` **Returning a multierror only if there are errors** If you build a `multierror.Error`, you can use the `ErrorOrNil` function to return an `error` implementation only if there are errors to return: ```go var result *multierror.Error // ... accumulate errors here // Return the `error` only if errors were added to the multierror, otherwise // return nil since there are no errors. return result.ErrorOrNil() ``` ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-multierror/append.go ================================================ package multierror // Append is a helper function that will append more errors // onto an Error in order to create a larger multi-error. // // If err is not a multierror.Error, then it will be turned into // one. If any of the errs are multierr.Error, they will be flattened // one level into err. // Any nil errors within errs will be ignored. If err is nil, a new // *Error will be returned. func Append(err error, errs ...error) *Error { switch err := err.(type) { case *Error: // Typed nils can reach here, so initialize if we are nil if err == nil { err = new(Error) } // Go through each error and flatten for _, e := range errs { switch e := e.(type) { case *Error: if e != nil { err.Errors = append(err.Errors, e.Errors...) } default: if e != nil { err.Errors = append(err.Errors, e) } } } return err default: newErrs := make([]error, 0, len(errs)+1) if err != nil { newErrs = append(newErrs, err) } newErrs = append(newErrs, errs...) return Append(&Error{}, newErrs...) } } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-multierror/flatten.go ================================================ package multierror // Flatten flattens the given error, merging any *Errors together into // a single *Error. func Flatten(err error) error { // If it isn't an *Error, just return the error as-is if _, ok := err.(*Error); !ok { return err } // Otherwise, make the result and flatten away! flatErr := new(Error) flatten(err, flatErr) return flatErr } func flatten(err error, flatErr *Error) { switch err := err.(type) { case *Error: for _, e := range err.Errors { flatten(e, flatErr) } default: flatErr.Errors = append(flatErr.Errors, err) } } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-multierror/format.go ================================================ package multierror import ( "fmt" "strings" ) // ErrorFormatFunc is a function callback that is called by Error to // turn the list of errors into a string. type ErrorFormatFunc func([]error) string // ListFormatFunc is a basic formatter that outputs the number of errors // that occurred along with a bullet point list of the errors. func ListFormatFunc(es []error) string { if len(es) == 1 { return fmt.Sprintf("1 error occurred:\n\t* %s\n\n", es[0]) } points := make([]string, len(es)) for i, err := range es { points[i] = fmt.Sprintf("* %s", err) } return fmt.Sprintf( "%d errors occurred:\n\t%s\n\n", len(es), strings.Join(points, "\n\t")) } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-multierror/group.go ================================================ package multierror import "sync" // Group is a collection of goroutines which return errors that need to be // coalesced. type Group struct { mutex sync.Mutex err *Error wg sync.WaitGroup } // Go calls the given function in a new goroutine. // // If the function returns an error it is added to the group multierror which // is returned by Wait. func (g *Group) Go(f func() error) { g.wg.Add(1) go func() { defer g.wg.Done() if err := f(); err != nil { g.mutex.Lock() g.err = Append(g.err, err) g.mutex.Unlock() } }() } // Wait blocks until all function calls from the Go method have returned, then // returns the multierror. func (g *Group) Wait() *Error { g.wg.Wait() g.mutex.Lock() defer g.mutex.Unlock() return g.err } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-multierror/multierror.go ================================================ package multierror import ( "errors" "fmt" ) // Error is an error type to track multiple errors. This is used to // accumulate errors in cases and return them as a single "error". type Error struct { Errors []error ErrorFormat ErrorFormatFunc } func (e *Error) Error() string { fn := e.ErrorFormat if fn == nil { fn = ListFormatFunc } return fn(e.Errors) } // ErrorOrNil returns an error interface if this Error represents // a list of errors, or returns nil if the list of errors is empty. This // function is useful at the end of accumulation to make sure that the value // returned represents the existence of errors. func (e *Error) ErrorOrNil() error { if e == nil { return nil } if len(e.Errors) == 0 { return nil } return e } func (e *Error) GoString() string { return fmt.Sprintf("*%#v", *e) } // WrappedErrors returns the list of errors that this Error is wrapping. It is // an implementation of the errwrap.Wrapper interface so that multierror.Error // can be used with that library. // // This method is not safe to be called concurrently. Unlike accessing the // Errors field directly, this function also checks if the multierror is nil to // prevent a null-pointer panic. It satisfies the errwrap.Wrapper interface. func (e *Error) WrappedErrors() []error { if e == nil { return nil } return e.Errors } // Unwrap returns an error from Error (or nil if there are no errors). // This error returned will further support Unwrap to get the next error, // etc. The order will match the order of Errors in the multierror.Error // at the time of calling. // // The resulting error supports errors.As/Is/Unwrap so you can continue // to use the stdlib errors package to introspect further. // // This will perform a shallow copy of the errors slice. Any errors appended // to this error after calling Unwrap will not be available until a new // Unwrap is called on the multierror.Error. func (e *Error) Unwrap() error { // If we have no errors then we do nothing if e == nil || len(e.Errors) == 0 { return nil } // If we have exactly one error, we can just return that directly. if len(e.Errors) == 1 { return e.Errors[0] } // Shallow copy the slice errs := make([]error, len(e.Errors)) copy(errs, e.Errors) return chain(errs) } // chain implements the interfaces necessary for errors.Is/As/Unwrap to // work in a deterministic way with multierror. A chain tracks a list of // errors while accounting for the current represented error. This lets // Is/As be meaningful. // // Unwrap returns the next error. In the cleanest form, Unwrap would return // the wrapped error here but we can't do that if we want to properly // get access to all the errors. Instead, users are recommended to use // Is/As to get the correct error type out. // // Precondition: []error is non-empty (len > 0) type chain []error // Error implements the error interface func (e chain) Error() string { return e[0].Error() } // Unwrap implements errors.Unwrap by returning the next error in the // chain or nil if there are no more errors. func (e chain) Unwrap() error { if len(e) == 1 { return nil } return e[1:] } // As implements errors.As by attempting to map to the current value. func (e chain) As(target interface{}) bool { return errors.As(e[0], target) } // Is implements errors.Is by comparing the current value directly. func (e chain) Is(target error) bool { return errors.Is(e[0], target) } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-multierror/prefix.go ================================================ package multierror import ( "fmt" "github.com/hashicorp/errwrap" ) // Prefix is a helper function that will prefix some text // to the given error. If the error is a multierror.Error, then // it will be prefixed to each wrapped error. // // This is useful to use when appending multiple multierrors // together in order to give better scoping. func Prefix(err error, prefix string) error { if err == nil { return nil } format := fmt.Sprintf("%s {{err}}", prefix) switch err := err.(type) { case *Error: // Typed nils can reach here, so initialize if we are nil if err == nil { err = new(Error) } // Wrap each of the errors for i, e := range err.Errors { err.Errors[i] = errwrap.Wrapf(format, e) } return err default: return errwrap.Wrapf(format, err) } } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-multierror/sort.go ================================================ package multierror // Len implements sort.Interface function for length func (err Error) Len() int { return len(err.Errors) } // Swap implements sort.Interface function for swapping elements func (err Error) Swap(i, j int) { err.Errors[i], err.Errors[j] = err.Errors[j], err.Errors[i] } // Less implements sort.Interface function for determining order func (err Error) Less(i, j int) bool { return err.Errors[i].Error() < err.Errors[j].Error() } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-retryablehttp/.gitignore ================================================ .idea/ *.iml *.test .vscode/ ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-retryablehttp/.go-version ================================================ 1.23 ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-retryablehttp/.golangci.yml ================================================ # Copyright (c) HashiCorp, Inc. # SPDX-License-Identifier: MPL-2.0 linters: disable-all: true enable: - errcheck - staticcheck - gosimple - govet output_format: colored-line-number ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-retryablehttp/CHANGELOG.md ================================================ ## 0.7.7 (May 30, 2024) BUG FIXES: - client: avoid potentially leaking URL-embedded basic authentication credentials in logs (#158) ## 0.7.6 (May 9, 2024) ENHANCEMENTS: - client: support a `RetryPrepare` function for modifying the request before retrying (#216) - client: support HTTP-date values for `Retry-After` header value (#138) - client: avoid reading entire body when the body is a `*bytes.Reader` (#197) BUG FIXES: - client: fix a broken check for invalid server certificate in go 1.20+ (#210) ## 0.7.5 (Nov 8, 2023) BUG FIXES: - client: fixes an issue where the request body is not preserved on temporary redirects or re-established HTTP/2 connections (#207) ## 0.7.4 (Jun 6, 2023) BUG FIXES: - client: fixing an issue where the Content-Type header wouldn't be sent with an empty payload when using HTTP/2 (#194) ## 0.7.3 (May 15, 2023) Initial release ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-retryablehttp/CODEOWNERS ================================================ # Each line is a file pattern followed by one or more owners. # More on CODEOWNERS files: https://help.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners # Default owner * @hashicorp/team-ip-compliance @hashicorp/go-retryablehttp-maintainers # Add override rules below. Each line is a file/folder pattern followed by one or more owners. # Being an owner means those groups or individuals will be added as reviewers to PRs affecting # those areas of the code. # Examples: # /docs/ @docs-team # *.js @js-team # *.go @go-team ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-retryablehttp/LICENSE ================================================ Copyright (c) 2015 HashiCorp, Inc. Mozilla Public License, version 2.0 1. Definitions 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means a. that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or b. that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: a. any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or b. any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: a. under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and b. under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: a. for any code that a Contributor has removed from Covered Software; or b. for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or c. under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: a. such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and b. You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. 6. Disclaimer of Warranty Covered Software is provided under this License on an "as is" basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer. 7. Limitation of Liability Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party's negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You. 8. Litigation Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-retryablehttp/Makefile ================================================ default: test test: go vet ./... go test -v -race ./... -coverprofile=coverage.out updatedeps: go get -f -t -u ./... go get -f -u ./... .PHONY: default test updatedeps ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-retryablehttp/README.md ================================================ go-retryablehttp ================ [![Build Status](http://img.shields.io/travis/hashicorp/go-retryablehttp.svg?style=flat-square)][travis] [![Go Documentation](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)][godocs] [travis]: http://travis-ci.org/hashicorp/go-retryablehttp [godocs]: http://godoc.org/github.com/hashicorp/go-retryablehttp The `retryablehttp` package provides a familiar HTTP client interface with automatic retries and exponential backoff. It is a thin wrapper over the standard `net/http` client library and exposes nearly the same public API. This makes `retryablehttp` very easy to drop into existing programs. `retryablehttp` performs automatic retries under certain conditions. Mainly, if an error is returned by the client (connection errors, etc.), or if a 500-range response code is received (except 501), then a retry is invoked after a wait period. Otherwise, the response is returned and left to the caller to interpret. The main difference from `net/http` is that requests which take a request body (POST/PUT et. al) can have the body provided in a number of ways (some more or less efficient) that allow "rewinding" the request body if the initial request fails so that the full request can be attempted again. See the [godoc](http://godoc.org/github.com/hashicorp/go-retryablehttp) for more details. Version 0.6.0 and before are compatible with Go prior to 1.12. From 0.6.1 onward, Go 1.12+ is required. From 0.6.7 onward, Go 1.13+ is required. Example Use =========== Using this library should look almost identical to what you would do with `net/http`. The most simple example of a GET request is shown below: ```go resp, err := retryablehttp.Get("/foo") if err != nil { panic(err) } ``` The returned response object is an `*http.Response`, the same thing you would usually get from `net/http`. Had the request failed one or more times, the above call would block and retry with exponential backoff. ## Getting a stdlib `*http.Client` with retries It's possible to convert a `*retryablehttp.Client` directly to a `*http.Client`. This makes use of retryablehttp broadly applicable with minimal effort. Simply configure a `*retryablehttp.Client` as you wish, and then call `StandardClient()`: ```go retryClient := retryablehttp.NewClient() retryClient.RetryMax = 10 standardClient := retryClient.StandardClient() // *http.Client ``` For more usage and examples see the [pkg.go.dev](https://pkg.go.dev/github.com/hashicorp/go-retryablehttp). ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-retryablehttp/cert_error_go119.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 //go:build !go1.20 // +build !go1.20 package retryablehttp import "crypto/x509" func isCertError(err error) bool { _, ok := err.(x509.UnknownAuthorityError) return ok } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-retryablehttp/cert_error_go120.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 //go:build go1.20 // +build go1.20 package retryablehttp import "crypto/tls" func isCertError(err error) bool { _, ok := err.(*tls.CertificateVerificationError) return ok } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-retryablehttp/client.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 // Package retryablehttp provides a familiar HTTP client interface with // automatic retries and exponential backoff. It is a thin wrapper over the // standard net/http client library and exposes nearly the same public API. // This makes retryablehttp very easy to drop into existing programs. // // retryablehttp performs automatic retries under certain conditions. Mainly, if // an error is returned by the client (connection errors etc), or if a 500-range // response is received, then a retry is invoked. Otherwise, the response is // returned and left to the caller to interpret. // // Requests which take a request body should provide a non-nil function // parameter. The best choice is to provide either a function satisfying // ReaderFunc which provides multiple io.Readers in an efficient manner, a // *bytes.Buffer (the underlying raw byte slice will be used) or a raw byte // slice. As it is a reference type, and we will wrap it as needed by readers, // we can efficiently re-use the request body without needing to copy it. If an // io.Reader (such as a *bytes.Reader) is provided, the full body will be read // prior to the first request, and will be efficiently re-used for any retries. // ReadSeeker can be used, but some users have observed occasional data races // between the net/http library and the Seek functionality of some // implementations of ReadSeeker, so should be avoided if possible. package retryablehttp import ( "bytes" "context" "fmt" "io" "log" "math" "math/rand" "net/http" "net/url" "os" "regexp" "strconv" "strings" "sync" "time" cleanhttp "github.com/hashicorp/go-cleanhttp" ) var ( // Default retry configuration defaultRetryWaitMin = 1 * time.Second defaultRetryWaitMax = 30 * time.Second defaultRetryMax = 4 // defaultLogger is the logger provided with defaultClient defaultLogger = log.New(os.Stderr, "", log.LstdFlags) // defaultClient is used for performing requests without explicitly making // a new client. It is purposely private to avoid modifications. defaultClient = NewClient() // We need to consume response bodies to maintain http connections, but // limit the size we consume to respReadLimit. respReadLimit = int64(4096) // timeNow sets the function that returns the current time. // This defaults to time.Now. Changes to this should only be done in tests. timeNow = time.Now // A regular expression to match the error returned by net/http when the // configured number of redirects is exhausted. This error isn't typed // specifically so we resort to matching on the error string. redirectsErrorRe = regexp.MustCompile(`stopped after \d+ redirects\z`) // A regular expression to match the error returned by net/http when the // scheme specified in the URL is invalid. This error isn't typed // specifically so we resort to matching on the error string. schemeErrorRe = regexp.MustCompile(`unsupported protocol scheme`) // A regular expression to match the error returned by net/http when a // request header or value is invalid. This error isn't typed // specifically so we resort to matching on the error string. invalidHeaderErrorRe = regexp.MustCompile(`invalid header`) // A regular expression to match the error returned by net/http when the // TLS certificate is not trusted. This error isn't typed // specifically so we resort to matching on the error string. notTrustedErrorRe = regexp.MustCompile(`certificate is not trusted`) ) // ReaderFunc is the type of function that can be given natively to NewRequest type ReaderFunc func() (io.Reader, error) // ResponseHandlerFunc is a type of function that takes in a Response, and does something with it. // The ResponseHandlerFunc is called when the HTTP client successfully receives a response and the // CheckRetry function indicates that a retry of the base request is not necessary. // If an error is returned from this function, the CheckRetry policy will be used to determine // whether to retry the whole request (including this handler). // // Make sure to check status codes! Even if the request was completed it may have a non-2xx status code. // // The response body is not automatically closed. It must be closed either by the ResponseHandlerFunc or // by the caller out-of-band. Failure to do so will result in a memory leak. type ResponseHandlerFunc func(*http.Response) error // LenReader is an interface implemented by many in-memory io.Reader's. Used // for automatically sending the right Content-Length header when possible. type LenReader interface { Len() int } // Request wraps the metadata needed to create HTTP requests. type Request struct { // body is a seekable reader over the request body payload. This is // used to rewind the request data in between retries. body ReaderFunc responseHandler ResponseHandlerFunc // Embed an HTTP request directly. This makes a *Request act exactly // like an *http.Request so that all meta methods are supported. *http.Request } // WithContext returns wrapped Request with a shallow copy of underlying *http.Request // with its context changed to ctx. The provided ctx must be non-nil. func (r *Request) WithContext(ctx context.Context) *Request { return &Request{ body: r.body, responseHandler: r.responseHandler, Request: r.Request.WithContext(ctx), } } // SetResponseHandler allows setting the response handler. func (r *Request) SetResponseHandler(fn ResponseHandlerFunc) { r.responseHandler = fn } // BodyBytes allows accessing the request body. It is an analogue to // http.Request's Body variable, but it returns a copy of the underlying data // rather than consuming it. // // This function is not thread-safe; do not call it at the same time as another // call, or at the same time this request is being used with Client.Do. func (r *Request) BodyBytes() ([]byte, error) { if r.body == nil { return nil, nil } body, err := r.body() if err != nil { return nil, err } buf := new(bytes.Buffer) _, err = buf.ReadFrom(body) if err != nil { return nil, err } return buf.Bytes(), nil } // SetBody allows setting the request body. // // It is useful if a new body needs to be set without constructing a new Request. func (r *Request) SetBody(rawBody interface{}) error { bodyReader, contentLength, err := getBodyReaderAndContentLength(rawBody) if err != nil { return err } r.body = bodyReader r.ContentLength = contentLength if bodyReader != nil { r.GetBody = func() (io.ReadCloser, error) { body, err := bodyReader() if err != nil { return nil, err } if rc, ok := body.(io.ReadCloser); ok { return rc, nil } return io.NopCloser(body), nil } } else { r.GetBody = func() (io.ReadCloser, error) { return http.NoBody, nil } } return nil } // WriteTo allows copying the request body into a writer. // // It writes data to w until there's no more data to write or // when an error occurs. The return int64 value is the number of bytes // written. Any error encountered during the write is also returned. // The signature matches io.WriterTo interface. func (r *Request) WriteTo(w io.Writer) (int64, error) { body, err := r.body() if err != nil { return 0, err } if c, ok := body.(io.Closer); ok { defer c.Close() } return io.Copy(w, body) } func getBodyReaderAndContentLength(rawBody interface{}) (ReaderFunc, int64, error) { var bodyReader ReaderFunc var contentLength int64 switch body := rawBody.(type) { // If they gave us a function already, great! Use it. case ReaderFunc: bodyReader = body tmp, err := body() if err != nil { return nil, 0, err } if lr, ok := tmp.(LenReader); ok { contentLength = int64(lr.Len()) } if c, ok := tmp.(io.Closer); ok { c.Close() } case func() (io.Reader, error): bodyReader = body tmp, err := body() if err != nil { return nil, 0, err } if lr, ok := tmp.(LenReader); ok { contentLength = int64(lr.Len()) } if c, ok := tmp.(io.Closer); ok { c.Close() } // If a regular byte slice, we can read it over and over via new // readers case []byte: buf := body bodyReader = func() (io.Reader, error) { return bytes.NewReader(buf), nil } contentLength = int64(len(buf)) // If a bytes.Buffer we can read the underlying byte slice over and // over case *bytes.Buffer: buf := body bodyReader = func() (io.Reader, error) { return bytes.NewReader(buf.Bytes()), nil } contentLength = int64(buf.Len()) // We prioritize *bytes.Reader here because we don't really want to // deal with it seeking so want it to match here instead of the // io.ReadSeeker case. case *bytes.Reader: snapshot := *body bodyReader = func() (io.Reader, error) { r := snapshot return &r, nil } contentLength = int64(body.Len()) // Compat case case io.ReadSeeker: raw := body bodyReader = func() (io.Reader, error) { _, err := raw.Seek(0, 0) return io.NopCloser(raw), err } if lr, ok := raw.(LenReader); ok { contentLength = int64(lr.Len()) } // Read all in so we can reset case io.Reader: buf, err := io.ReadAll(body) if err != nil { return nil, 0, err } if len(buf) == 0 { bodyReader = func() (io.Reader, error) { return http.NoBody, nil } contentLength = 0 } else { bodyReader = func() (io.Reader, error) { return bytes.NewReader(buf), nil } contentLength = int64(len(buf)) } // No body provided, nothing to do case nil: // Unrecognized type default: return nil, 0, fmt.Errorf("cannot handle type %T", rawBody) } return bodyReader, contentLength, nil } // FromRequest wraps an http.Request in a retryablehttp.Request func FromRequest(r *http.Request) (*Request, error) { bodyReader, _, err := getBodyReaderAndContentLength(r.Body) if err != nil { return nil, err } // Could assert contentLength == r.ContentLength return &Request{body: bodyReader, Request: r}, nil } // NewRequest creates a new wrapped request. func NewRequest(method, url string, rawBody interface{}) (*Request, error) { return NewRequestWithContext(context.Background(), method, url, rawBody) } // NewRequestWithContext creates a new wrapped request with the provided context. // // The context controls the entire lifetime of a request and its response: // obtaining a connection, sending the request, and reading the response headers and body. func NewRequestWithContext(ctx context.Context, method, url string, rawBody interface{}) (*Request, error) { httpReq, err := http.NewRequestWithContext(ctx, method, url, nil) if err != nil { return nil, err } req := &Request{ Request: httpReq, } if err := req.SetBody(rawBody); err != nil { return nil, err } return req, nil } // Logger interface allows to use other loggers than // standard log.Logger. type Logger interface { Printf(string, ...interface{}) } // LeveledLogger is an interface that can be implemented by any logger or a // logger wrapper to provide leveled logging. The methods accept a message // string and a variadic number of key-value pairs. For log.Printf style // formatting where message string contains a format specifier, use Logger // interface. type LeveledLogger interface { Error(msg string, keysAndValues ...interface{}) Info(msg string, keysAndValues ...interface{}) Debug(msg string, keysAndValues ...interface{}) Warn(msg string, keysAndValues ...interface{}) } // hookLogger adapts an LeveledLogger to Logger for use by the existing hook functions // without changing the API. type hookLogger struct { LeveledLogger } func (h hookLogger) Printf(s string, args ...interface{}) { h.Info(fmt.Sprintf(s, args...)) } // RequestLogHook allows a function to run before each retry. The HTTP // request which will be made, and the retry number (0 for the initial // request) are available to users. The internal logger is exposed to // consumers. type RequestLogHook func(Logger, *http.Request, int) // ResponseLogHook is like RequestLogHook, but allows running a function // on each HTTP response. This function will be invoked at the end of // every HTTP request executed, regardless of whether a subsequent retry // needs to be performed or not. If the response body is read or closed // from this method, this will affect the response returned from Do(). type ResponseLogHook func(Logger, *http.Response) // CheckRetry specifies a policy for handling retries. It is called // following each request with the response and error values returned by // the http.Client. If CheckRetry returns false, the Client stops retrying // and returns the response to the caller. If CheckRetry returns an error, // that error value is returned in lieu of the error from the request. The // Client will close any response body when retrying, but if the retry is // aborted it is up to the CheckRetry callback to properly close any // response body before returning. type CheckRetry func(ctx context.Context, resp *http.Response, err error) (bool, error) // Backoff specifies a policy for how long to wait between retries. // It is called after a failing request to determine the amount of time // that should pass before trying again. type Backoff func(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration // ErrorHandler is called if retries are expired, containing the last status // from the http library. If not specified, default behavior for the library is // to close the body and return an error indicating how many tries were // attempted. If overriding this, be sure to close the body if needed. type ErrorHandler func(resp *http.Response, err error, numTries int) (*http.Response, error) // PrepareRetry is called before retry operation. It can be used for example to re-sign the request type PrepareRetry func(req *http.Request) error // Client is used to make HTTP requests. It adds additional functionality // like automatic retries to tolerate minor outages. type Client struct { HTTPClient *http.Client // Internal HTTP client. Logger interface{} // Customer logger instance. Can be either Logger or LeveledLogger RetryWaitMin time.Duration // Minimum time to wait RetryWaitMax time.Duration // Maximum time to wait RetryMax int // Maximum number of retries // RequestLogHook allows a user-supplied function to be called // before each retry. RequestLogHook RequestLogHook // ResponseLogHook allows a user-supplied function to be called // with the response from each HTTP request executed. ResponseLogHook ResponseLogHook // CheckRetry specifies the policy for handling retries, and is called // after each request. The default policy is DefaultRetryPolicy. CheckRetry CheckRetry // Backoff specifies the policy for how long to wait between retries Backoff Backoff // ErrorHandler specifies the custom error handler to use, if any ErrorHandler ErrorHandler // PrepareRetry can prepare the request for retry operation, for example re-sign it PrepareRetry PrepareRetry loggerInit sync.Once clientInit sync.Once } // NewClient creates a new Client with default settings. func NewClient() *Client { return &Client{ HTTPClient: cleanhttp.DefaultPooledClient(), Logger: defaultLogger, RetryWaitMin: defaultRetryWaitMin, RetryWaitMax: defaultRetryWaitMax, RetryMax: defaultRetryMax, CheckRetry: DefaultRetryPolicy, Backoff: DefaultBackoff, } } func (c *Client) logger() interface{} { c.loggerInit.Do(func() { if c.Logger == nil { return } switch c.Logger.(type) { case Logger, LeveledLogger: // ok default: // This should happen in dev when they are setting Logger and work on code, not in prod. panic(fmt.Sprintf("invalid logger type passed, must be Logger or LeveledLogger, was %T", c.Logger)) } }) return c.Logger } // DefaultRetryPolicy provides a default callback for Client.CheckRetry, which // will retry on connection errors and server errors. func DefaultRetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) { // do not retry on context.Canceled or context.DeadlineExceeded if ctx.Err() != nil { return false, ctx.Err() } // don't propagate other errors shouldRetry, _ := baseRetryPolicy(resp, err) return shouldRetry, nil } // ErrorPropagatedRetryPolicy is the same as DefaultRetryPolicy, except it // propagates errors back instead of returning nil. This allows you to inspect // why it decided to retry or not. func ErrorPropagatedRetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) { // do not retry on context.Canceled or context.DeadlineExceeded if ctx.Err() != nil { return false, ctx.Err() } return baseRetryPolicy(resp, err) } func baseRetryPolicy(resp *http.Response, err error) (bool, error) { if err != nil { if v, ok := err.(*url.Error); ok { // Don't retry if the error was due to too many redirects. if redirectsErrorRe.MatchString(v.Error()) { return false, v } // Don't retry if the error was due to an invalid protocol scheme. if schemeErrorRe.MatchString(v.Error()) { return false, v } // Don't retry if the error was due to an invalid header. if invalidHeaderErrorRe.MatchString(v.Error()) { return false, v } // Don't retry if the error was due to TLS cert verification failure. if notTrustedErrorRe.MatchString(v.Error()) { return false, v } if isCertError(v.Err) { return false, v } } // The error is likely recoverable so retry. return true, nil } // 429 Too Many Requests is recoverable. Sometimes the server puts // a Retry-After response header to indicate when the server is // available to start processing request from client. if resp.StatusCode == http.StatusTooManyRequests { return true, nil } // Check the response code. We retry on 500-range responses to allow // the server time to recover, as 500's are typically not permanent // errors and may relate to outages on the server side. This will catch // invalid response codes as well, like 0 and 999. if resp.StatusCode == 0 || (resp.StatusCode >= 500 && resp.StatusCode != http.StatusNotImplemented) { return true, fmt.Errorf("unexpected HTTP status %s", resp.Status) } return false, nil } // DefaultBackoff provides a default callback for Client.Backoff which // will perform exponential backoff based on the attempt number and limited // by the provided minimum and maximum durations. // // It also tries to parse Retry-After response header when a http.StatusTooManyRequests // (HTTP Code 429) is found in the resp parameter. Hence it will return the number of // seconds the server states it may be ready to process more requests from this client. func DefaultBackoff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration { if resp != nil { if resp.StatusCode == http.StatusTooManyRequests || resp.StatusCode == http.StatusServiceUnavailable { if sleep, ok := parseRetryAfterHeader(resp.Header["Retry-After"]); ok { return sleep } } } mult := math.Pow(2, float64(attemptNum)) * float64(min) sleep := time.Duration(mult) if float64(sleep) != mult || sleep > max { sleep = max } return sleep } // parseRetryAfterHeader parses the Retry-After header and returns the // delay duration according to the spec: https://httpwg.org/specs/rfc7231.html#header.retry-after // The bool returned will be true if the header was successfully parsed. // Otherwise, the header was either not present, or was not parseable according to the spec. // // Retry-After headers come in two flavors: Seconds or HTTP-Date // // Examples: // * Retry-After: Fri, 31 Dec 1999 23:59:59 GMT // * Retry-After: 120 func parseRetryAfterHeader(headers []string) (time.Duration, bool) { if len(headers) == 0 || headers[0] == "" { return 0, false } header := headers[0] // Retry-After: 120 if sleep, err := strconv.ParseInt(header, 10, 64); err == nil { if sleep < 0 { // a negative sleep doesn't make sense return 0, false } return time.Second * time.Duration(sleep), true } // Retry-After: Fri, 31 Dec 1999 23:59:59 GMT retryTime, err := time.Parse(time.RFC1123, header) if err != nil { return 0, false } if until := retryTime.Sub(timeNow()); until > 0 { return until, true } // date is in the past return 0, true } // LinearJitterBackoff provides a callback for Client.Backoff which will // perform linear backoff based on the attempt number and with jitter to // prevent a thundering herd. // // min and max here are *not* absolute values. The number to be multiplied by // the attempt number will be chosen at random from between them, thus they are // bounding the jitter. // // For instance: // * To get strictly linear backoff of one second increasing each retry, set // both to one second (1s, 2s, 3s, 4s, ...) // * To get a small amount of jitter centered around one second increasing each // retry, set to around one second, such as a min of 800ms and max of 1200ms // (892ms, 2102ms, 2945ms, 4312ms, ...) // * To get extreme jitter, set to a very wide spread, such as a min of 100ms // and a max of 20s (15382ms, 292ms, 51321ms, 35234ms, ...) func LinearJitterBackoff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration { // attemptNum always starts at zero but we want to start at 1 for multiplication attemptNum++ if max <= min { // Unclear what to do here, or they are the same, so return min * // attemptNum return min * time.Duration(attemptNum) } // Seed rand; doing this every time is fine source := rand.New(rand.NewSource(int64(time.Now().Nanosecond()))) // Pick a random number that lies somewhere between the min and max and // multiply by the attemptNum. attemptNum starts at zero so we always // increment here. We first get a random percentage, then apply that to the // difference between min and max, and add to min. jitter := source.Float64() * float64(max-min) jitterMin := int64(jitter) + int64(min) return time.Duration(jitterMin * int64(attemptNum)) } // RateLimitLinearJitterBackoff wraps the retryablehttp.LinearJitterBackoff. // It first checks if the response status code is http.StatusTooManyRequests // (HTTP Code 429) or http.StatusServiceUnavailable (HTTP Code 503). If it is // and the response contains a Retry-After response header, it will wait the // amount of time specified by the header. Otherwise, this calls // LinearJitterBackoff. func RateLimitLinearJitterBackoff(min, max time.Duration, attemptNum int, resp *http.Response) time.Duration { if resp != nil { if resp.StatusCode == http.StatusTooManyRequests || resp.StatusCode == http.StatusServiceUnavailable { if sleep, ok := parseRetryAfterHeader(resp.Header["Retry-After"]); ok { return sleep } } } return LinearJitterBackoff(min, max, attemptNum, resp) } // PassthroughErrorHandler is an ErrorHandler that directly passes through the // values from the net/http library for the final request. The body is not // closed. func PassthroughErrorHandler(resp *http.Response, err error, _ int) (*http.Response, error) { return resp, err } // Do wraps calling an HTTP method with retries. func (c *Client) Do(req *Request) (*http.Response, error) { c.clientInit.Do(func() { if c.HTTPClient == nil { c.HTTPClient = cleanhttp.DefaultPooledClient() } }) logger := c.logger() if logger != nil { switch v := logger.(type) { case LeveledLogger: v.Debug("performing request", "method", req.Method, "url", redactURL(req.URL)) case Logger: v.Printf("[DEBUG] %s %s", req.Method, redactURL(req.URL)) } } var resp *http.Response var attempt int var shouldRetry bool var doErr, respErr, checkErr, prepareErr error for i := 0; ; i++ { doErr, respErr, prepareErr = nil, nil, nil attempt++ // Always rewind the request body when non-nil. if req.body != nil { body, err := req.body() if err != nil { c.HTTPClient.CloseIdleConnections() return resp, err } if c, ok := body.(io.ReadCloser); ok { req.Body = c } else { req.Body = io.NopCloser(body) } } if c.RequestLogHook != nil { switch v := logger.(type) { case LeveledLogger: c.RequestLogHook(hookLogger{v}, req.Request, i) case Logger: c.RequestLogHook(v, req.Request, i) default: c.RequestLogHook(nil, req.Request, i) } } // Attempt the request resp, doErr = c.HTTPClient.Do(req.Request) // Check if we should continue with retries. shouldRetry, checkErr = c.CheckRetry(req.Context(), resp, doErr) if !shouldRetry && doErr == nil && req.responseHandler != nil { respErr = req.responseHandler(resp) shouldRetry, checkErr = c.CheckRetry(req.Context(), resp, respErr) } err := doErr if respErr != nil { err = respErr } if err != nil { switch v := logger.(type) { case LeveledLogger: v.Error("request failed", "error", err, "method", req.Method, "url", redactURL(req.URL)) case Logger: v.Printf("[ERR] %s %s request failed: %v", req.Method, redactURL(req.URL), err) } } else { // Call this here to maintain the behavior of logging all requests, // even if CheckRetry signals to stop. if c.ResponseLogHook != nil { // Call the response logger function if provided. switch v := logger.(type) { case LeveledLogger: c.ResponseLogHook(hookLogger{v}, resp) case Logger: c.ResponseLogHook(v, resp) default: c.ResponseLogHook(nil, resp) } } } if !shouldRetry { break } // We do this before drainBody because there's no need for the I/O if // we're breaking out remain := c.RetryMax - i if remain <= 0 { break } // We're going to retry, consume any response to reuse the connection. if doErr == nil { c.drainBody(resp.Body) } wait := c.Backoff(c.RetryWaitMin, c.RetryWaitMax, i, resp) if logger != nil { desc := fmt.Sprintf("%s %s", req.Method, redactURL(req.URL)) if resp != nil { desc = fmt.Sprintf("%s (status: %d)", desc, resp.StatusCode) } switch v := logger.(type) { case LeveledLogger: v.Debug("retrying request", "request", desc, "timeout", wait, "remaining", remain) case Logger: v.Printf("[DEBUG] %s: retrying in %s (%d left)", desc, wait, remain) } } timer := time.NewTimer(wait) select { case <-req.Context().Done(): timer.Stop() c.HTTPClient.CloseIdleConnections() return nil, req.Context().Err() case <-timer.C: } // Make shallow copy of http Request so that we can modify its body // without racing against the closeBody call in persistConn.writeLoop. httpreq := *req.Request req.Request = &httpreq if c.PrepareRetry != nil { if err := c.PrepareRetry(req.Request); err != nil { prepareErr = err break } } } // this is the closest we have to success criteria if doErr == nil && respErr == nil && checkErr == nil && prepareErr == nil && !shouldRetry { return resp, nil } defer c.HTTPClient.CloseIdleConnections() var err error if prepareErr != nil { err = prepareErr } else if checkErr != nil { err = checkErr } else if respErr != nil { err = respErr } else { err = doErr } if c.ErrorHandler != nil { return c.ErrorHandler(resp, err, attempt) } // By default, we close the response body and return an error without // returning the response if resp != nil { c.drainBody(resp.Body) } // this means CheckRetry thought the request was a failure, but didn't // communicate why if err == nil { return nil, fmt.Errorf("%s %s giving up after %d attempt(s)", req.Method, redactURL(req.URL), attempt) } return nil, fmt.Errorf("%s %s giving up after %d attempt(s): %w", req.Method, redactURL(req.URL), attempt, err) } // Try to read the response body so we can reuse this connection. func (c *Client) drainBody(body io.ReadCloser) { defer body.Close() _, err := io.Copy(io.Discard, io.LimitReader(body, respReadLimit)) if err != nil { if c.logger() != nil { switch v := c.logger().(type) { case LeveledLogger: v.Error("error reading response body", "error", err) case Logger: v.Printf("[ERR] error reading response body: %v", err) } } } } // Get is a shortcut for doing a GET request without making a new client. func Get(url string) (*http.Response, error) { return defaultClient.Get(url) } // Get is a convenience helper for doing simple GET requests. func (c *Client) Get(url string) (*http.Response, error) { req, err := NewRequest("GET", url, nil) if err != nil { return nil, err } return c.Do(req) } // Head is a shortcut for doing a HEAD request without making a new client. func Head(url string) (*http.Response, error) { return defaultClient.Head(url) } // Head is a convenience method for doing simple HEAD requests. func (c *Client) Head(url string) (*http.Response, error) { req, err := NewRequest("HEAD", url, nil) if err != nil { return nil, err } return c.Do(req) } // Post is a shortcut for doing a POST request without making a new client. // The bodyType parameter sets the "Content-Type" header of the request. func Post(url, bodyType string, body interface{}) (*http.Response, error) { return defaultClient.Post(url, bodyType, body) } // Post is a convenience method for doing simple POST requests. // The bodyType parameter sets the "Content-Type" header of the request. func (c *Client) Post(url, bodyType string, body interface{}) (*http.Response, error) { req, err := NewRequest("POST", url, body) if err != nil { return nil, err } req.Header.Set("Content-Type", bodyType) return c.Do(req) } // PostForm is a shortcut to perform a POST with form data without creating // a new client. func PostForm(url string, data url.Values) (*http.Response, error) { return defaultClient.PostForm(url, data) } // PostForm is a convenience method for doing simple POST operations using // pre-filled url.Values form data. func (c *Client) PostForm(url string, data url.Values) (*http.Response, error) { return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) } // StandardClient returns a stdlib *http.Client with a custom Transport, which // shims in a *retryablehttp.Client for added retries. func (c *Client) StandardClient() *http.Client { return &http.Client{ Transport: &RoundTripper{Client: c}, } } // Taken from url.URL#Redacted() which was introduced in go 1.15. // We can switch to using it directly if we'll bump the minimum required go version. func redactURL(u *url.URL) string { if u == nil { return "" } ru := *u if _, has := ru.User.Password(); has { ru.User = url.UserPassword(ru.User.Username(), "xxxxx") } return ru.String() } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-retryablehttp/roundtripper.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package retryablehttp import ( "errors" "net/http" "net/url" "sync" ) // RoundTripper implements the http.RoundTripper interface, using a retrying // HTTP client to execute requests. // // It is important to note that retryablehttp doesn't always act exactly as a // RoundTripper should. This is highly dependent on the retryable client's // configuration. type RoundTripper struct { // The client to use during requests. If nil, the default retryablehttp // client and settings will be used. Client *Client // once ensures that the logic to initialize the default client runs at // most once, in a single thread. once sync.Once } // init initializes the underlying retryable client. func (rt *RoundTripper) init() { if rt.Client == nil { rt.Client = NewClient() } } // RoundTrip satisfies the http.RoundTripper interface. func (rt *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { rt.once.Do(rt.init) // Convert the request to be retryable. retryableReq, err := FromRequest(req) if err != nil { return nil, err } // Execute the request. resp, err := rt.Client.Do(retryableReq) // If we got an error returned by standard library's `Do` method, unwrap it // otherwise we will wind up erroneously re-nesting the error. if _, ok := err.(*url.Error); ok { return resp, errors.Unwrap(err) } return resp, err } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-rootcerts/.travis.yml ================================================ sudo: false language: go go: - 1.6 branches: only: - master script: make test ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-rootcerts/LICENSE ================================================ Mozilla Public License, version 2.0 1. Definitions 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means a. that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or b. that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: a. any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or b. any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: a. under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and b. under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: a. for any code that a Contributor has removed from Covered Software; or b. for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or c. under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: a. such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and b. You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. 6. Disclaimer of Warranty Covered Software is provided under this License on an "as is" basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer. 7. Limitation of Liability Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party's negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You. 8. Litigation Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-rootcerts/Makefile ================================================ TEST?=./... test: go test $(TEST) $(TESTARGS) -timeout=3s -parallel=4 go vet $(TEST) go test $(TEST) -race .PHONY: test ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-rootcerts/README.md ================================================ # rootcerts Functions for loading root certificates for TLS connections. ----- Go's standard library `crypto/tls` provides a common mechanism for configuring TLS connections in `tls.Config`. The `RootCAs` field on this struct is a pool of certificates for the client to use as a trust store when verifying server certificates. This library contains utility functions for loading certificates destined for that field, as well as one other important thing: When the `RootCAs` field is `nil`, the standard library attempts to load the host's root CA set. This behavior is OS-specific, and the Darwin implementation contains [a bug that prevents trusted certificates from the System and Login keychains from being loaded][1]. This library contains Darwin-specific behavior that works around that bug. [1]: https://github.com/golang/go/issues/14514 ## Example Usage Here's a snippet demonstrating how this library is meant to be used: ```go func httpClient() (*http.Client, error) tlsConfig := &tls.Config{} err := rootcerts.ConfigureTLS(tlsConfig, &rootcerts.Config{ CAFile: os.Getenv("MYAPP_CAFILE"), CAPath: os.Getenv("MYAPP_CAPATH"), Certificate: os.Getenv("MYAPP_CERTIFICATE"), }) if err != nil { return nil, err } c := cleanhttp.DefaultClient() t := cleanhttp.DefaultTransport() t.TLSClientConfig = tlsConfig c.Transport = t return c, nil } ``` ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-rootcerts/doc.go ================================================ // Package rootcerts contains functions to aid in loading CA certificates for // TLS connections. // // In addition, its default behavior on Darwin works around an open issue [1] // in Go's crypto/x509 that prevents certicates from being loaded from the // System or Login keychains. // // [1] https://github.com/golang/go/issues/14514 package rootcerts ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-rootcerts/rootcerts.go ================================================ package rootcerts import ( "crypto/tls" "crypto/x509" "errors" "fmt" "io/ioutil" "os" "path/filepath" ) // Config determines where LoadCACerts will load certificates from. When CAFile, // CACertificate and CAPath are blank, this library's functions will either load // system roots explicitly and return them, or set the CertPool to nil to allow // Go's standard library to load system certs. type Config struct { // CAFile is a path to a PEM-encoded certificate file or bundle. Takes // precedence over CACertificate and CAPath. CAFile string // CACertificate is a PEM-encoded certificate or bundle. Takes precedence // over CAPath. CACertificate []byte // CAPath is a path to a directory populated with PEM-encoded certificates. CAPath string } // ConfigureTLS sets up the RootCAs on the provided tls.Config based on the // Config specified. func ConfigureTLS(t *tls.Config, c *Config) error { if t == nil { return nil } pool, err := LoadCACerts(c) if err != nil { return err } t.RootCAs = pool return nil } // LoadCACerts loads a CertPool based on the Config specified. func LoadCACerts(c *Config) (*x509.CertPool, error) { if c == nil { c = &Config{} } if c.CAFile != "" { return LoadCAFile(c.CAFile) } if len(c.CACertificate) != 0 { return AppendCertificate(c.CACertificate) } if c.CAPath != "" { return LoadCAPath(c.CAPath) } return LoadSystemCAs() } // LoadCAFile loads a single PEM-encoded file from the path specified. func LoadCAFile(caFile string) (*x509.CertPool, error) { pool := x509.NewCertPool() pem, err := ioutil.ReadFile(caFile) if err != nil { return nil, fmt.Errorf("Error loading CA File: %s", err) } ok := pool.AppendCertsFromPEM(pem) if !ok { return nil, fmt.Errorf("Error loading CA File: Couldn't parse PEM in: %s", caFile) } return pool, nil } // AppendCertificate appends an in-memory PEM-encoded certificate or bundle and returns a pool. func AppendCertificate(ca []byte) (*x509.CertPool, error) { pool := x509.NewCertPool() ok := pool.AppendCertsFromPEM(ca) if !ok { return nil, errors.New("Error appending CA: Couldn't parse PEM") } return pool, nil } // LoadCAPath walks the provided path and loads all certificates encounted into // a pool. func LoadCAPath(caPath string) (*x509.CertPool, error) { pool := x509.NewCertPool() walkFn := func(path string, info os.FileInfo, err error) error { if err != nil { return err } if info.IsDir() { return nil } pem, err := ioutil.ReadFile(path) if err != nil { return fmt.Errorf("Error loading file from CAPath: %s", err) } ok := pool.AppendCertsFromPEM(pem) if !ok { return fmt.Errorf("Error loading CA Path: Couldn't parse PEM in: %s", path) } return nil } err := filepath.Walk(caPath, walkFn) if err != nil { return nil, err } return pool, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-rootcerts/rootcerts_base.go ================================================ // +build !darwin package rootcerts import "crypto/x509" // LoadSystemCAs does nothing on non-Darwin systems. We return nil so that // default behavior of standard TLS config libraries is triggered, which is to // load system certs. func LoadSystemCAs() (*x509.CertPool, error) { return nil, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-rootcerts/rootcerts_darwin.go ================================================ package rootcerts import ( "crypto/x509" "os/exec" "path" "github.com/mitchellh/go-homedir" ) // LoadSystemCAs has special behavior on Darwin systems to work around func LoadSystemCAs() (*x509.CertPool, error) { pool := x509.NewCertPool() for _, keychain := range certKeychains() { err := addCertsFromKeychain(pool, keychain) if err != nil { return nil, err } } return pool, nil } func addCertsFromKeychain(pool *x509.CertPool, keychain string) error { cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", keychain) data, err := cmd.Output() if err != nil { return err } pool.AppendCertsFromPEM(data) return nil } func certKeychains() []string { keychains := []string{ "/System/Library/Keychains/SystemRootCertificates.keychain", "/Library/Keychains/System.keychain", } home, err := homedir.Dir() if err == nil { loginKeychain := path.Join(home, "Library", "Keychains", "login.keychain") keychains = append(keychains, loginKeychain) } return keychains } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-secure-stdlib/parseutil/LICENSE ================================================ Copyright (c) 2020 HashiCorp, Inc. Mozilla Public License, version 2.0 1. Definitions 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means a. that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or b. that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: a. any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or b. any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: a. under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and b. under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: a. for any code that a Contributor has removed from Covered Software; or b. for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or c. under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: a. such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and b. You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. 6. Disclaimer of Warranty Covered Software is provided under this License on an "as is" basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer. 7. Limitation of Liability Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party's negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You. 8. Litigation Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-secure-stdlib/parseutil/normalize.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package parseutil import ( "fmt" "net" "net/url" "strings" ) // general delimiters as defined in RFC-3986 §2.2 // See: https://www.rfc-editor.org/rfc/rfc3986#section-2.2 const genDelims = ":/?#[]@" func normalizeHostPort(host string, port string) (string, error) { if host == "" { return "", fmt.Errorf("empty hostname") } if ip := net.ParseIP(host); ip != nil { if ip.To4() == nil && ip.To16() != nil && port == "" { // this is a unique case, host is ipv6 and requires brackets due to // being part of a url, but they won't be added by net.JoinHostPort // as there is no port // See: https://www.rfc-editor.org/rfc/rfc3986#section-3.2.2 return "[" + ip.String() + "]", nil } host = ip.String() } else if strings.Contains(host, ":") { // host is an invalid ipv6 literal. // hosts cannot contain certain reserved characters, including ":" // See: https://www.rfc-editor.org/rfc/rfc3986#section-2.2, // https://www.rfc-editor.org/rfc/rfc3986#section-3.2.2 return "", fmt.Errorf("host contains an invalid IPv6 literal") } if port == "" { return host, nil } return net.JoinHostPort(host, port), nil } func parseUrl(addr string) (string, error) { if u, err := url.Parse(addr); err == nil { if strings.HasSuffix(u.Host, ":") { return "", fmt.Errorf("url has malformed host: missing port value after colon") } if u.Host, err = normalizeHostPort(u.Hostname(), u.Port()); err != nil { return "", err } return u.String(), nil } return "", fmt.Errorf("failed to parse address") } // NormalizeAddr takes an address as a string and returns a normalized copy. // If the address is a URL, IP Address, or host:port address that includes an // IPv6 address, the normalized copy will be conformant with RFC-5952 §4. If // the address cannot be parsed, an error will be returned. // // There are two valid formats: // // - hosts: "host" // - may be any of: IPv6 literal, IPv4 literal, dns name, or [sub]domain name // - IPv6 literals cannot be encapsulated within square brackets in this format // // - URIs: "[scheme://] [user@] host [:port] [/path] [?query] [#frag]" // - format should conform with RFC-3986 §3 or else the returned address may // be parsed and formatted incorrectly // - hosts containing IPv6 literals MUST be encapsulated within square brackets, // as defined in RFC-3986 §3.2.2 and RFC-5952 §6 // - all non-host components are optional // // See: // - https://www.rfc-editor.org/rfc/rfc5952 // - https://www.rfc-editor.org/rfc/rfc3986 func NormalizeAddr(address string) (string, error) { if address == "" { return "", fmt.Errorf("empty address") } if strings.HasPrefix(address, "[") && strings.HasSuffix(address, "]") { return "", fmt.Errorf("address cannot be encapsulated by brackets") } if ip := net.ParseIP(address); ip != nil { return ip.String(), nil } // if the provided address does not have a scheme provided, attempt to // provide one and re-parse the result. this is done by looking for the // first general delimiter and checking if it exists or if it's not a colon // or by subsequently checking if the first character of the address is a // letter or a colon or if the colon is part of "://" // See: https://www.rfc-editor.org/rfc/rfc3986#section-3 // // though the first character being a colon is not mentioned in the scheme // spec, we check for it as url.Parse will read certain invalid ipv6 // addresses as valid urls, and we want to avoid that idx := strings.IndexAny(address, genDelims) switch { case idx < 0: fallthrough case address[idx] != ':': fallthrough // by this point we already know that idx > 0 and that address[idx] == ':' case idx > 1 && !strings.HasPrefix(address[idx:], "://"): const scheme = "default://" // attempt to parse it as a url. we only want to try this func when we // know for sure it has a scheme, since it will parse ANYTHING, but // just put it into u.Path when called without the scheme u, err := parseUrl(scheme + address) if err != nil { return "", err } return strings.TrimPrefix(u, scheme), nil default: return parseUrl(address) } } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-secure-stdlib/parseutil/parsepath.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package parseutil import ( "errors" "fmt" "io/ioutil" "net/url" "os" "strings" ) var ( ErrNotAUrl = errors.New("not a url") ErrNotParsed = errors.New("not a parsed value") ) type options struct { errorOnMissingEnv bool noTrimSpaces bool } type option func() optionFunc type optionFunc func(*options) // ParsePath parses a URL with schemes file://, env://, or any other. Depending // on the scheme it will return specific types of data: // // * file:// will return a string with the file's contents // // * env:// will return a string with the env var's contents // // * Anything else will return the string as it was. Functionally this means // anything for which Go's `url.Parse` function does not throw an error. If you // want to ensure that this function errors if a known scheme is not found, use // MustParsePath. // // On error, we return the original string along with the error. The caller can // switch on errors.Is(err, ErrNotAUrl) to understand whether it was the parsing // step that errored or something else (such as a file not found). This is // useful to attempt to read a non-URL string from some resource, but where the // original input may simply be a valid string of that type. func ParsePath(path string, options ...option) (string, error) { return parsePath(path, false, options) } // MustParsePath behaves like ParsePath but will return ErrNotAUrl if the value // is not a URL with a scheme that can be parsed by this function. func MustParsePath(path string, options ...option) (string, error) { return parsePath(path, true, options) } func parsePath(path string, mustParse bool, passedOptions []option) (string, error) { var opts options for _, o := range passedOptions { of := o() of(&opts) } trimmedPath := strings.TrimSpace(path) parsed, err := url.Parse(trimmedPath) if err != nil { err = fmt.Errorf("error parsing url (%q): %w", err.Error(), ErrNotAUrl) if opts.noTrimSpaces { return path, err } return trimmedPath, err } switch parsed.Scheme { case "file": contents, err := ioutil.ReadFile(strings.TrimPrefix(trimmedPath, "file://")) if err != nil { return trimmedPath, fmt.Errorf("error reading file at %s: %w", trimmedPath, err) } if opts.noTrimSpaces { return string(contents), nil } return strings.TrimSpace(string(contents)), nil case "env": envKey := strings.TrimPrefix(trimmedPath, "env://") envVal, ok := os.LookupEnv(envKey) if opts.errorOnMissingEnv && !ok { return "", fmt.Errorf("environment variable %s unset", envKey) } if opts.noTrimSpaces { return envVal, nil } return strings.TrimSpace(envVal), nil case "string": // Meant if there is a need to provide a string literal that is prefixed by one of these URL schemes but want to "escape" it, // e.g. "string://env://foo", in order to get the value "env://foo" val := strings.TrimPrefix(trimmedPath, "string://") if opts.noTrimSpaces { return val, nil } return strings.TrimSpace(val), nil default: if mustParse { return "", ErrNotParsed } return path, nil } } // When true, values returned from ParsePath won't have leading/trailing spaces trimmed. func WithNoTrimSpaces(noTrim bool) option { return func() optionFunc { return optionFunc(func(o *options) { o.noTrimSpaces = noTrim }) } } // When true, if an environment variable is unset, an error will be returned rather than the empty string. func WithErrorOnMissingEnv(errorOnMissingEnv bool) option { return func() optionFunc { return optionFunc(func(o *options) { o.errorOnMissingEnv = errorOnMissingEnv }) } } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-secure-stdlib/parseutil/parseutil.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package parseutil import ( "encoding/json" "errors" "fmt" "math" "regexp" "strconv" "strings" "time" "github.com/hashicorp/go-secure-stdlib/strutil" sockaddr "github.com/hashicorp/go-sockaddr" "github.com/mitchellh/mapstructure" ) var ( validCapacityString = regexp.MustCompile("^[\t ]*([0-9]+)[\t ]?([kmgtKMGT][iI]?[bB])?[\t ]*$") ErrDurationMultiplicationOverflow = errors.New("multiplication of durations resulted in overflow, one operand may be too large") ) // ParseCapacityString parses a capacity string and returns the number of bytes it represents. // Capacity strings are things like 5gib or 10MB. Supported prefixes are kb, kib, mb, mib, gb, // gib, tb, tib, which are not case sensitive. If no prefix is present, the number is assumed // to be in bytes already. func ParseCapacityString(in interface{}) (uint64, error) { var cap uint64 jsonIn, ok := in.(json.Number) if ok { in = jsonIn.String() } switch inp := in.(type) { case nil: // return default of zero case string: if inp == "" { return cap, nil } matches := validCapacityString.FindStringSubmatch(inp) // no sub-groups means we couldn't parse it if len(matches) <= 1 { return cap, errors.New("could not parse capacity from input") } var multiplier uint64 = 1 switch strings.ToLower(matches[2]) { case "kb": multiplier = 1000 case "kib": multiplier = 1024 case "mb": multiplier = 1000 * 1000 case "mib": multiplier = 1024 * 1024 case "gb": multiplier = 1000 * 1000 * 1000 case "gib": multiplier = 1024 * 1024 * 1024 case "tb": multiplier = 1000 * 1000 * 1000 * 1000 case "tib": multiplier = 1024 * 1024 * 1024 * 1024 } size, err := strconv.ParseUint(matches[1], 10, 64) if err != nil { return cap, err } cap = size * multiplier case int: cap = uint64(inp) case int32: cap = uint64(inp) case int64: cap = uint64(inp) case uint: cap = uint64(inp) case uint32: cap = uint64(inp) case uint64: cap = uint64(inp) case float32: cap = uint64(inp) case float64: cap = uint64(inp) default: return cap, errors.New("could not parse capacity from input") } return cap, nil } // Parse a duration from an arbitrary value (a string or numeric value) into // a time.Duration; when units are missing (such as when a numeric type is // provided), the duration is assumed to be in seconds. func ParseDurationSecond(in interface{}) (time.Duration, error) { var dur time.Duration jsonIn, ok := in.(json.Number) if ok { in = jsonIn.String() } var err error switch inp := in.(type) { case nil: // return default of zero case string: if inp == "" { return dur, nil } if v, err := strconv.ParseInt(inp, 10, 64); err == nil { return overflowMul(time.Duration(v), time.Second) } if strings.HasSuffix(inp, "d") { v, err := strconv.ParseInt(inp[:len(inp)-1], 10, 64) if err != nil { return dur, err } return overflowMul(time.Duration(v), 24*time.Hour) } var err error if dur, err = time.ParseDuration(inp); err != nil { return dur, err } case int: dur, err = overflowMul(time.Duration(inp), time.Second) case int32: dur, err = overflowMul(time.Duration(inp), time.Second) case int64: dur, err = overflowMul(time.Duration(inp), time.Second) case uint: dur, err = overflowMul(time.Duration(inp), time.Second) case uint32: dur, err = overflowMul(time.Duration(inp), time.Second) case uint64: dur, err = overflowMul(time.Duration(inp), time.Second) case float32: dur, err = overflowMul(time.Duration(inp), time.Second) case float64: dur, err = overflowMul(time.Duration(inp), time.Second) case time.Duration: dur = inp default: return 0, errors.New("could not parse duration from input") } if err != nil { dur = time.Duration(0) } return dur, err } // Multiplication of durations could overflow, this performs multiplication while erroring out if an overflow occurs func overflowMul(a time.Duration, b time.Duration) (time.Duration, error) { x := a * b if a != 0 && x/a != b { return time.Duration(0), ErrDurationMultiplicationOverflow } return x, nil } // Parse an absolute timestamp from the provided arbitrary value (string or // numeric value). When an untyped numeric value is provided, it is assumed // to be seconds from the Unix Epoch. func ParseAbsoluteTime(in interface{}) (time.Time, error) { var t time.Time switch inp := in.(type) { case nil: // return default of zero return t, nil case string: // Allow RFC3339 with nanoseconds, or without, // or an epoch time as an integer. var err error t, err = time.Parse(time.RFC3339Nano, inp) if err == nil { break } t, err = time.Parse(time.RFC3339, inp) if err == nil { break } epochTime, err := strconv.ParseInt(inp, 10, 64) if err == nil { t = time.Unix(epochTime, 0) break } return t, errors.New("could not parse string as date and time") case json.Number: epochTime, err := inp.Int64() if err != nil { return t, err } t = time.Unix(epochTime, 0) case int: t = time.Unix(int64(inp), 0) case int32: t = time.Unix(int64(inp), 0) case int64: t = time.Unix(inp, 0) case uint: t = time.Unix(int64(inp), 0) case uint32: t = time.Unix(int64(inp), 0) case uint64: t = time.Unix(int64(inp), 0) default: return t, errors.New("could not parse time from input type") } return t, nil } // ParseInt takes an arbitrary value (either a string or numeric type) and // parses it as an int64 value. This value is assumed to be larger than the // provided type, but cannot safely be cast. // // When the end value is bounded (such as an int value), it is recommended // to instead call SafeParseInt or SafeParseIntRange to safely cast to a // more restrictive type. func ParseInt(in interface{}) (int64, error) { var ret int64 jsonIn, ok := in.(json.Number) if ok { in = jsonIn.String() } switch in.(type) { case string: inp := in.(string) if inp == "" { return 0, nil } var err error left, err := strconv.ParseInt(inp, 10, 64) if err != nil { return ret, err } ret = left case int: ret = int64(in.(int)) case int32: ret = int64(in.(int32)) case int64: ret = in.(int64) case uint: ret = int64(in.(uint)) case uint32: ret = int64(in.(uint32)) case uint64: ret = int64(in.(uint64)) default: return 0, errors.New("could not parse value from input") } return ret, nil } // ParseDirectIntSlice behaves similarly to ParseInt, but accepts typed // slices, returning a slice of int64s. // // If the starting value may not be in slice form (e.g.. a bare numeric value // could be provided), it is suggested to call ParseIntSlice instead. func ParseDirectIntSlice(in interface{}) ([]int64, error) { var ret []int64 switch in.(type) { case []int: for _, v := range in.([]int) { ret = append(ret, int64(v)) } case []int32: for _, v := range in.([]int32) { ret = append(ret, int64(v)) } case []int64: // For consistency to ensure callers can always modify ret without // impacting in. for _, v := range in.([]int64) { ret = append(ret, v) } case []uint: for _, v := range in.([]uint) { ret = append(ret, int64(v)) } case []uint32: for _, v := range in.([]uint32) { ret = append(ret, int64(v)) } case []uint64: for _, v := range in.([]uint64) { ret = append(ret, int64(v)) } case []json.Number: for _, v := range in.([]json.Number) { element, err := ParseInt(v) if err != nil { return nil, err } ret = append(ret, element) } case []string: for _, v := range in.([]string) { element, err := ParseInt(v) if err != nil { return nil, err } ret = append(ret, element) } default: return nil, errors.New("could not parse value from input") } return ret, nil } // ParseIntSlice is a helper function for handling upgrades of optional // slices; that is, if the API accepts a type similar to , // nicely handle the common cases of providing only an int-ish, providing // an actual slice of int-ishes, or providing a comma-separated list of // numbers. // // When []int64 is not the desired final type (or the values should be // range-bound), it is suggested to call SafeParseIntSlice or // SafeParseIntSliceRange instead. func ParseIntSlice(in interface{}) ([]int64, error) { if ret, err := ParseInt(in); err == nil { return []int64{ret}, nil } if ret, err := ParseDirectIntSlice(in); err == nil { return ret, nil } if strings, err := ParseCommaStringSlice(in); err == nil { var ret []int64 for _, v := range strings { if v == "" { // Ignore empty fields continue } element, err := ParseInt(v) if err != nil { return nil, err } ret = append(ret, element) } return ret, nil } return nil, errors.New("could not parse value from input") } // Parses the provided arbitrary value as a boolean-like value. func ParseBool(in interface{}) (bool, error) { var result bool if err := mapstructure.WeakDecode(in, &result); err != nil { return false, err } return result, nil } // Parses the provided arbitrary value as a string. func ParseString(in interface{}) (string, error) { var result string if err := mapstructure.WeakDecode(in, &result); err != nil { return "", err } return result, nil } // Parses the provided string-like value as a comma-separated list of values. func ParseCommaStringSlice(in interface{}) ([]string, error) { jsonIn, ok := in.(json.Number) if ok { in = jsonIn.String() } rawString, ok := in.(string) if ok && rawString == "" { return []string{}, nil } var result []string config := &mapstructure.DecoderConfig{ Result: &result, WeaklyTypedInput: true, DecodeHook: mapstructure.StringToSliceHookFunc(","), } decoder, err := mapstructure.NewDecoder(config) if err != nil { return nil, err } if err := decoder.Decode(in); err != nil { return nil, err } return strutil.TrimStrings(result), nil } // Parses the specified value as one or more addresses, separated by commas. func ParseAddrs(addrs interface{}) ([]*sockaddr.SockAddrMarshaler, error) { out := make([]*sockaddr.SockAddrMarshaler, 0) stringAddrs := make([]string, 0) switch addrs.(type) { case string: stringAddrs = strutil.ParseArbitraryStringSlice(addrs.(string), ",") if len(stringAddrs) == 0 { return nil, fmt.Errorf("unable to parse addresses from %v", addrs) } case []string: stringAddrs = addrs.([]string) case []interface{}: for _, v := range addrs.([]interface{}) { stringAddr, ok := v.(string) if !ok { return nil, fmt.Errorf("error parsing %v as string", v) } stringAddrs = append(stringAddrs, stringAddr) } default: return nil, fmt.Errorf("unknown address input type %T", addrs) } for _, addr := range stringAddrs { sa, err := sockaddr.NewSockAddr(addr) if err != nil { return nil, fmt.Errorf("error parsing address %q: %w", addr, err) } out = append(out, &sockaddr.SockAddrMarshaler{ SockAddr: sa, }) } return out, nil } // Parses the provided arbitrary value (see ParseInt), ensuring it is within // the specified range (inclusive of bounds). If this range corresponds to a // smaller type, the returned value can then be safely cast without risking // overflow. func SafeParseIntRange(in interface{}, min int64, max int64) (int64, error) { raw, err := ParseInt(in) if err != nil { return 0, err } if raw < min || raw > max { return 0, fmt.Errorf("error parsing int value; out of range [%v to %v]: %v", min, max, raw) } return raw, nil } // Parses the specified arbitrary value (see ParseInt), ensuring that the // resulting value is within the range for an int value. If no error occurred, // the caller knows no overflow occurred. func SafeParseInt(in interface{}) (int, error) { raw, err := SafeParseIntRange(in, math.MinInt, math.MaxInt) return int(raw), err } // Parses the provided arbitrary value (see ParseIntSlice) into a slice of // int64 values, ensuring each is within the specified range (inclusive of // bounds). If this range corresponds to a smaller type, the returned value // can then be safely cast without risking overflow. // // If elements is positive, it is used to ensure the resulting slice is // bounded above by that many number of elements (inclusive). func SafeParseIntSliceRange(in interface{}, minValue int64, maxValue int64, elements int) ([]int64, error) { raw, err := ParseIntSlice(in) if err != nil { return nil, err } if elements > 0 && len(raw) > elements { return nil, fmt.Errorf("error parsing value from input: got %v but expected at most %v elements", len(raw), elements) } for index, value := range raw { if value < minValue || value > maxValue { return nil, fmt.Errorf("error parsing value from input: element %v was outside of range [%v to %v]: %v", index, minValue, maxValue, value) } } return raw, nil } // Parses the provided arbitrary value (see ParseIntSlice) into a slice of // int values, ensuring the each resulting value in the slice is within the // range for an int value. If no error occurred, the caller knows no overflow // occurred. // // If elements is positive, it is used to ensure the resulting slice is // bounded above by that many number of elements (inclusive). func SafeParseIntSlice(in interface{}, elements int) ([]int, error) { raw, err := SafeParseIntSliceRange(in, math.MinInt, math.MaxInt, elements) if err != nil || raw == nil { return nil, err } var result = make([]int, 0, len(raw)) for _, element := range raw { result = append(result, int(element)) } return result, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-secure-stdlib/strutil/LICENSE ================================================ Mozilla Public License, version 2.0 1. Definitions 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means a. that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or b. that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: a. any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or b. any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: a. under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and b. under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: a. for any code that a Contributor has removed from Covered Software; or b. for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or c. under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: a. such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and b. You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. 6. Disclaimer of Warranty Covered Software is provided under this License on an "as is" basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer. 7. Limitation of Liability Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party's negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You. 8. Litigation Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-secure-stdlib/strutil/strutil.go ================================================ package strutil import ( "encoding/base64" "encoding/json" "fmt" "sort" "strings" "unicode" glob "github.com/ryanuber/go-glob" ) // StrListContainsGlob looks for a string in a list of strings and allows // globs. func StrListContainsGlob(haystack []string, needle string) bool { for _, item := range haystack { if glob.Glob(item, needle) { return true } } return false } // StrListContains looks for a string in a list of strings. func StrListContains(haystack []string, needle string) bool { for _, item := range haystack { if item == needle { return true } } return false } // StrListContainsCaseInsensitive looks for a string in a list of strings. func StrListContainsCaseInsensitive(haystack []string, needle string) bool { for _, item := range haystack { if strings.EqualFold(item, needle) { return true } } return false } // StrListSubset checks if a given list is a subset // of another set func StrListSubset(super, sub []string) bool { for _, item := range sub { if !StrListContains(super, item) { return false } } return true } // ParseDedupAndSortStrings parses a comma separated list of strings // into a slice of strings. The return slice will be sorted and will // not contain duplicate or empty items. func ParseDedupAndSortStrings(input string, sep string) []string { input = strings.TrimSpace(input) parsed := []string{} if input == "" { // Don't return nil return parsed } return RemoveDuplicates(strings.Split(input, sep), false) } // ParseDedupLowercaseAndSortStrings parses a comma separated list of // strings into a slice of strings. The return slice will be sorted and // will not contain duplicate or empty items. The values will be converted // to lower case. func ParseDedupLowercaseAndSortStrings(input string, sep string) []string { input = strings.TrimSpace(input) parsed := []string{} if input == "" { // Don't return nil return parsed } return RemoveDuplicates(strings.Split(input, sep), true) } // ParseKeyValues parses a comma separated list of `=` tuples // into a map[string]string. func ParseKeyValues(input string, out map[string]string, sep string) error { if out == nil { return fmt.Errorf("'out is nil") } keyValues := ParseDedupLowercaseAndSortStrings(input, sep) if len(keyValues) == 0 { return nil } for _, keyValue := range keyValues { shards := strings.Split(keyValue, "=") if len(shards) != 2 { return fmt.Errorf("invalid format") } key := strings.TrimSpace(shards[0]) value := strings.TrimSpace(shards[1]) if key == "" || value == "" { return fmt.Errorf("invalid pair: key: %q value: %q", key, value) } out[key] = value } return nil } // 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 // // Input will be parsed into the output parameter, which should // be a non-nil map[string]string. func ParseArbitraryKeyValues(input string, out map[string]string, sep string) error { input = strings.TrimSpace(input) if input == "" { return nil } if out == nil { return fmt.Errorf("'out' is nil") } // Try to base64 decode the input. If successful, consider the decoded // value as input. inputBytes, err := base64.StdEncoding.DecodeString(input) if err == nil { input = string(inputBytes) } // Try to JSON unmarshal the input. If successful, consider that the // metadata was supplied as JSON input. err = json.Unmarshal([]byte(input), &out) if err != nil { // If JSON unmarshaling fails, consider that the input was // supplied as a comma separated string of 'key=value' pairs. if err = ParseKeyValues(input, out, sep); err != nil { return fmt.Errorf("failed to parse the input: %w", err) } } // Validate the parsed input for key, value := range out { if key != "" && value == "" { return fmt.Errorf("invalid value for key %q", key) } } return nil } // ParseStringSlice parses a `sep`-separated list of strings into a // []string with surrounding whitespace removed. // // The output will always be a valid slice but may be of length zero. func ParseStringSlice(input string, sep string) []string { input = strings.TrimSpace(input) if input == "" { return []string{} } splitStr := strings.Split(input, sep) ret := make([]string, len(splitStr)) for i, val := range splitStr { ret[i] = strings.TrimSpace(val) } return ret } // ParseArbitraryStringSlice parses arbitrary string slice. The input // can be one of the following: // * JSON string // * Base64 encoded JSON string // * `sep` separated list of values // * Base64-encoded string containing a `sep` separated list of values // // Note that the separator is ignored if the input is found to already be in a // structured format (e.g., JSON) // // The output will always be a valid slice but may be of length zero. func ParseArbitraryStringSlice(input string, sep string) []string { input = strings.TrimSpace(input) if input == "" { return []string{} } // Try to base64 decode the input. If successful, consider the decoded // value as input. inputBytes, err := base64.StdEncoding.DecodeString(input) if err == nil { input = string(inputBytes) } ret := []string{} // Try to JSON unmarshal the input. If successful, consider that the // metadata was supplied as JSON input. err = json.Unmarshal([]byte(input), &ret) if err != nil { // If JSON unmarshaling fails, consider that the input was // supplied as a separated string of values. return ParseStringSlice(input, sep) } if ret == nil { return []string{} } return ret } // TrimStrings takes a slice of strings and returns a slice of strings // with trimmed spaces func TrimStrings(items []string) []string { ret := make([]string, len(items)) for i, item := range items { ret[i] = strings.TrimSpace(item) } return ret } // RemoveDuplicates removes duplicate and empty elements from a slice of // strings. This also may convert the items in the slice to lower case and // returns a sorted slice. func RemoveDuplicates(items []string, lowercase bool) []string { itemsMap := make(map[string]struct{}, len(items)) for _, item := range items { item = strings.TrimSpace(item) if item == "" { continue } if lowercase { item = strings.ToLower(item) } itemsMap[item] = struct{}{} } items = make([]string, 0, len(itemsMap)) for item := range itemsMap { items = append(items, item) } sort.Strings(items) return items } // RemoveDuplicatesStable removes duplicate and empty elements from a slice of // strings, preserving order (and case) of the original slice. // In all cases, strings are compared after trimming whitespace // If caseInsensitive, strings will be compared after ToLower() func RemoveDuplicatesStable(items []string, caseInsensitive bool) []string { itemsMap := make(map[string]struct{}, len(items)) deduplicated := make([]string, 0, len(items)) for _, item := range items { key := strings.TrimSpace(item) if _, ok := itemsMap[key]; ok || key == "" { continue } if caseInsensitive { key = strings.ToLower(key) } if _, ok := itemsMap[key]; ok { continue } itemsMap[key] = struct{}{} deduplicated = append(deduplicated, item) } return deduplicated } // RemoveEmpty removes empty elements from a slice of // strings func RemoveEmpty(items []string) []string { if len(items) == 0 { return items } itemsSlice := make([]string, 0, len(items)) for _, item := range items { if item == "" { continue } itemsSlice = append(itemsSlice, item) } return itemsSlice } // EquivalentSlices checks whether the given string sets are equivalent, as in, // they contain the same values. func EquivalentSlices(a, b []string) bool { if a == nil && b == nil { return true } if a == nil || b == nil { return false } // First we'll build maps to ensure unique values mapA := make(map[string]struct{}, len(a)) mapB := make(map[string]struct{}, len(b)) for _, keyA := range a { mapA[keyA] = struct{}{} } for _, keyB := range b { mapB[keyB] = struct{}{} } // Now we'll build our checking slices sortedA := make([]string, 0, len(mapA)) sortedB := make([]string, 0, len(mapB)) for keyA := range mapA { sortedA = append(sortedA, keyA) } for keyB := range mapB { sortedB = append(sortedB, keyB) } sort.Strings(sortedA) sort.Strings(sortedB) // Finally, compare if len(sortedA) != len(sortedB) { return false } for i := range sortedA { if sortedA[i] != sortedB[i] { return false } } return true } // EqualStringMaps tests whether two map[string]string objects are equal. // Equal means both maps have the same sets of keys and values. This function // is 6-10x faster than a call to reflect.DeepEqual(). func EqualStringMaps(a, b map[string]string) bool { if len(a) != len(b) { return false } for k := range a { v, ok := b[k] if !ok || a[k] != v { return false } } return true } // StrListDelete removes the first occurrence of the given item from the slice // of strings if the item exists. func StrListDelete(s []string, d string) []string { if s == nil { return s } for index, element := range s { if element == d { return append(s[:index], s[index+1:]...) } } return s } // GlobbedStringsMatch compares item to val with support for a leading and/or // trailing wildcard '*' in item. func GlobbedStringsMatch(item, val string) bool { if len(item) < 2 { return val == item } hasPrefix := strings.HasPrefix(item, "*") hasSuffix := strings.HasSuffix(item, "*") if hasPrefix && hasSuffix { return strings.Contains(val, item[1:len(item)-1]) } else if hasPrefix { return strings.HasSuffix(val, item[1:]) } else if hasSuffix { return strings.HasPrefix(val, item[:len(item)-1]) } return val == item } // AppendIfMissing adds a string to a slice if the given string is not present func AppendIfMissing(slice []string, i string) []string { if StrListContains(slice, i) { return slice } return append(slice, i) } // MergeSlices adds an arbitrary number of slices together, uniquely func MergeSlices(args ...[]string) []string { all := map[string]struct{}{} for _, slice := range args { for _, v := range slice { all[v] = struct{}{} } } result := make([]string, 0, len(all)) for k := range all { result = append(result, k) } sort.Strings(result) return result } // Difference returns the set difference (A - B) of the two given slices. The // result will also remove any duplicated values in set A regardless of whether // that matches any values in set B. func Difference(a, b []string, lowercase bool) []string { if len(a) == 0 { return a } if len(b) == 0 { if !lowercase { return a } newA := make([]string, len(a)) for i, v := range a { newA[i] = strings.ToLower(v) } return newA } a = RemoveDuplicates(a, lowercase) b = RemoveDuplicates(b, lowercase) itemsMap := map[string]struct{}{} for _, aVal := range a { itemsMap[aVal] = struct{}{} } // Perform difference calculation for _, bVal := range b { if _, ok := itemsMap[bVal]; ok { delete(itemsMap, bVal) } } items := []string{} for item := range itemsMap { items = append(items, item) } sort.Strings(items) return items } // GetString attempts to retrieve a value from the provided map and assert that it is a string. If the key does not // exist in the map, this will return an empty string. If the key exists, but the value is not a string type, this will // return an error. If no map or key is provied, this will return an error func GetString(m map[string]interface{}, key string) (string, error) { if m == nil { return "", fmt.Errorf("missing map") } if key == "" { return "", fmt.Errorf("missing key") } rawVal, ok := m[key] if !ok { return "", nil } str, ok := rawVal.(string) if !ok { return "", fmt.Errorf("invalid value at %s: is a %T", key, rawVal) } return str, nil } // Printable returns true if all characters in the string are printable // according to Unicode func Printable(s string) bool { return strings.IndexFunc(s, func(c rune) bool { return !unicode.IsPrint(c) }) == -1 } // StringListToInterfaceList simply takes a []string and turns it into a // []interface{} to satisfy the input requirements for other library functions func StringListToInterfaceList(in []string) []interface{} { ret := make([]interface{}, len(in)) for i, v := range in { ret[i] = v } return ret } // Reverse reverses the input string func Reverse(in string) string { l := len(in) out := make([]byte, l) for i := 0; i <= l/2; i++ { out[i], out[l-1-i] = in[l-1-i], in[i] } return string(out) } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/.gitignore ================================================ # Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test *.prof .cover.out* coverage.html ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/GNUmakefile ================================================ TOOLS= golang.org/x/tools/cover GOCOVER_TMPFILE?= $(GOCOVER_FILE).tmp GOCOVER_FILE?= .cover.out GOCOVERHTML?= coverage.html FIND=`/usr/bin/which 2> /dev/null gfind find | /usr/bin/grep -v ^no | /usr/bin/head -n 1` XARGS=`/usr/bin/which 2> /dev/null gxargs xargs | /usr/bin/grep -v ^no | /usr/bin/head -n 1` test:: $(GOCOVER_FILE) @$(MAKE) -C cmd/sockaddr test cover:: coverage_report $(GOCOVER_FILE):: @${FIND} . -type d ! -path '*cmd*' ! -path '*.git*' -print0 | ${XARGS} -0 -I % sh -ec "cd % && rm -f $(GOCOVER_TMPFILE) && go test -coverprofile=$(GOCOVER_TMPFILE)" @echo 'mode: set' > $(GOCOVER_FILE) @${FIND} . -type f ! -path '*cmd*' ! -path '*.git*' -name "$(GOCOVER_TMPFILE)" -print0 | ${XARGS} -0 -n1 cat $(GOCOVER_TMPFILE) | grep -v '^mode: ' >> ${PWD}/$(GOCOVER_FILE) $(GOCOVERHTML): $(GOCOVER_FILE) go tool cover -html=$(GOCOVER_FILE) -o $(GOCOVERHTML) coverage_report:: $(GOCOVER_FILE) go tool cover -html=$(GOCOVER_FILE) audit_tools:: @go get -u github.com/golang/lint/golint && echo "Installed golint:" @go get -u github.com/fzipp/gocyclo && echo "Installed gocyclo:" @go get -u github.com/remyoudompheng/go-misc/deadcode && echo "Installed deadcode:" @go get -u github.com/client9/misspell/cmd/misspell && echo "Installed misspell:" @go get -u github.com/gordonklaus/ineffassign && echo "Installed ineffassign:" audit:: deadcode go tool vet -all *.go go tool vet -shadow=true *.go golint *.go ineffassign . gocyclo -over 65 *.go misspell *.go clean:: rm -f $(GOCOVER_FILE) $(GOCOVERHTML) dev:: @go build @$(MAKE) -B -C cmd/sockaddr sockaddr install:: @go install @$(MAKE) -C cmd/sockaddr install doc:: @echo Visit: http://127.0.0.1:6161/pkg/github.com/hashicorp/go-sockaddr/ godoc -http=:6161 -goroot $GOROOT world:: @set -e; \ for os in solaris darwin freebsd linux windows android; do \ for arch in amd64; do \ printf "Building on %s-%s\n" "$${os}" "$${arch}" ; \ env GOOS="$${os}" GOARCH="$${arch}" go build -o /dev/null; \ done; \ done $(MAKE) -C cmd/sockaddr world ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/LICENSE ================================================ Copyright (c) 2016 HashiCorp, Inc. Mozilla Public License Version 2.0 ================================== 1. Definitions -------------- 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or (b) any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions -------------------------------- 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and (b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: (a) for any code that a Contributor has removed from Covered Software; or (b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or (c) under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities ------------------- 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: (a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and (b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation --------------------------------------------------- If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination -------------- 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. ************************************************************************ * * * 6. Disclaimer of Warranty * * ------------------------- * * * * Covered Software is provided under this License on an "as is" * * basis, without warranty of any kind, either expressed, implied, or * * statutory, including, without limitation, warranties that the * * Covered Software is free of defects, merchantable, fit for a * * particular purpose or non-infringing. The entire risk as to the * * quality and performance of the Covered Software is with You. * * Should any Covered Software prove defective in any respect, You * * (not any Contributor) assume the cost of any necessary servicing, * * repair, or correction. This disclaimer of warranty constitutes an * * essential part of this License. No use of any Covered Software is * * authorized under this License except under this disclaimer. * * * ************************************************************************ ************************************************************************ * * * 7. Limitation of Liability * * -------------------------- * * * * Under no circumstances and under no legal theory, whether tort * * (including negligence), contract, or otherwise, shall any * * Contributor, or anyone who distributes Covered Software as * * permitted above, be liable to You for any direct, indirect, * * special, incidental, or consequential damages of any character * * including, without limitation, damages for lost profits, loss of * * goodwill, work stoppage, computer failure or malfunction, or any * * and all other commercial damages or losses, even if such party * * shall have been informed of the possibility of such damages. This * * limitation of liability shall not apply to liability for death or * * personal injury resulting from such party's negligence to the * * extent applicable law prohibits such limitation. Some * * jurisdictions do not allow the exclusion or limitation of * * incidental or consequential damages, so this exclusion and * * limitation may not apply to You. * * * ************************************************************************ 8. Litigation ------------- Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous ---------------- This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License --------------------------- 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice ------------------------------------------- This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice --------------------------------------------------------- This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/README.md ================================================ # go-sockaddr ## `sockaddr` Library Socket address convenience functions for Go. `go-sockaddr` is a convenience library that makes doing the right thing with IP addresses easy. `go-sockaddr` is loosely modeled after the UNIX `sockaddr_t` and creates a union of the family of `sockaddr_t` types (see below for an ascii diagram). Library documentation is available at [https://godoc.org/github.com/hashicorp/go-sockaddr](https://godoc.org/github.com/hashicorp/go-sockaddr). The primary intent of the library was to make it possible to define heuristics for selecting the correct IP addresses when a configuration is evaluated at runtime. See the [docs](https://godoc.org/github.com/hashicorp/go-sockaddr), [`template` package](https://godoc.org/github.com/hashicorp/go-sockaddr/template), tests, and [CLI utility](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr) for details and hints as to how to use this library. For example, with this library it is possible to find an IP address that: * is attached to a default route ([`GetDefaultInterfaces()`](https://godoc.org/github.com/hashicorp/go-sockaddr#GetDefaultInterfaces)) * is contained within a CIDR block ([`IfByNetwork()`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByNetwork)) * is an RFC1918 address ([`IfByRFC("1918")`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByRFC)) * is ordered ([`OrderedIfAddrBy(args)`](https://godoc.org/github.com/hashicorp/go-sockaddr#OrderedIfAddrBy) where `args` includes, but is not limited to, [`AscIfType`](https://godoc.org/github.com/hashicorp/go-sockaddr#AscIfType), [`AscNetworkSize`](https://godoc.org/github.com/hashicorp/go-sockaddr#AscNetworkSize)) * excludes all IPv6 addresses ([`IfByType("^(IPv4)$")`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByType)) * is larger than a `/32` ([`IfByMaskSize(32)`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByMaskSize)) * is not on a `down` interface ([`ExcludeIfs("flags", "down")`](https://godoc.org/github.com/hashicorp/go-sockaddr#ExcludeIfs)) * preferences an IPv6 address over an IPv4 address ([`SortIfByType()`](https://godoc.org/github.com/hashicorp/go-sockaddr#SortIfByType) + [`ReverseIfAddrs()`](https://godoc.org/github.com/hashicorp/go-sockaddr#ReverseIfAddrs)); and * excludes any IP in RFC6890 address ([`IfByRFC("6890")`](https://godoc.org/github.com/hashicorp/go-sockaddr#IfByRFC)) Or any combination or variation therein. There are also a few simple helper functions such as `GetPublicIP` and `GetPrivateIP` which both return strings and select the first public or private IP address on the default interface, respectively. Similarly, there is also a helper function called `GetInterfaceIP` which returns the first usable IP address on the named interface. ## `sockaddr` CLI Given the possible complexity of the `sockaddr` library, there is a CLI utility that accompanies the library, also called [`sockaddr`](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr). The [`sockaddr`](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr) utility exposes nearly all of the functionality of the library and can be used either as an administrative tool or testing tool. To install the [`sockaddr`](https://github.com/hashicorp/go-sockaddr/tree/master/cmd/sockaddr), run: ```text $ go install github.com/hashicorp/go-sockaddr/cmd/sockaddr@latest ``` If you're familiar with UNIX's `sockaddr` struct's, the following diagram mapping the C `sockaddr` (top) to `go-sockaddr` structs (bottom) and interfaces will be helpful: ``` +-------------------------------------------------------+ | | | sockaddr | | SockAddr | | | | +--------------+ +----------------------------------+ | | | sockaddr_un | | | | | | SockAddrUnix | | sockaddr_in{,6} | | | +--------------+ | IPAddr | | | | | | | | +-------------+ +--------------+ | | | | | sockaddr_in | | sockaddr_in6 | | | | | | IPv4Addr | | IPv6Addr | | | | | +-------------+ +--------------+ | | | | | | | +----------------------------------+ | | | +-------------------------------------------------------+ ``` ## Inspiration and Design There were many subtle inspirations that led to this design, but the most direct inspiration for the filtering syntax was OpenBSD's [`pf.conf(5)`](https://www.freebsd.org/cgi/man.cgi?query=pf.conf&apropos=0&sektion=0&arch=default&format=html#PARAMETERS) firewall syntax that lets you select the first IP address on a given named interface. The original problem stemmed from: * needing to create immutable images using [Packer](https://www.packer.io) that ran the [Consul](https://www.consul.io) process (Consul can only use one IP address at a time); * images that may or may not have multiple interfaces or IP addresses at runtime; and * we didn't want to rely on configuration management to render out the correct IP address if the VM image was being used in an auto-scaling group. Instead we needed some way to codify a heuristic that would correctly select the right IP address but the input parameters were not known when the image was created. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/doc.go ================================================ /* Package sockaddr is a Go implementation of the UNIX socket family data types and related helper functions. */ package sockaddr ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ifaddr.go ================================================ package sockaddr import "strings" // ifAddrAttrMap is a map of the IfAddr type-specific attributes. var ifAddrAttrMap map[AttrName]func(IfAddr) string var ifAddrAttrs []AttrName func init() { ifAddrAttrInit() } // GetPrivateIP returns a string with a single IP address that is part of RFC // 6890 and has a default route. If the system can't determine its IP address // or find an RFC 6890 IP address, an empty string will be returned instead. // This function is the `eval` equivalent of: // // ``` // $ sockaddr eval -r '{{GetPrivateInterfaces | attr "address"}}' /// ``` func GetPrivateIP() (string, error) { privateIfs, err := GetPrivateInterfaces() if err != nil { return "", err } if len(privateIfs) < 1 { return "", nil } ifAddr := privateIfs[0] ip := *ToIPAddr(ifAddr.SockAddr) return ip.NetIP().String(), nil } // GetPrivateIPs returns a string with all IP addresses that are part of RFC // 6890 (regardless of whether or not there is a default route, unlike // GetPublicIP). If the system can't find any RFC 6890 IP addresses, an empty // string will be returned instead. This function is the `eval` equivalent of: // // ``` // $ sockaddr eval -r '{{GetAllInterfaces | include "RFC" "6890" | join "address" " "}}' /// ``` func GetPrivateIPs() (string, error) { ifAddrs, err := GetAllInterfaces() if err != nil { return "", err } else if len(ifAddrs) < 1 { return "", nil } ifAddrs, _ = FilterIfByType(ifAddrs, TypeIP) if len(ifAddrs) == 0 { return "", nil } OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(ifAddrs) ifAddrs, _, err = IfByRFC("6890", ifAddrs) if err != nil { return "", err } else if len(ifAddrs) == 0 { return "", nil } _, ifAddrs, err = IfByRFC(ForwardingBlacklistRFC, ifAddrs) if err != nil { return "", err } else if len(ifAddrs) == 0 { return "", nil } ips := make([]string, 0, len(ifAddrs)) for _, ifAddr := range ifAddrs { ip := *ToIPAddr(ifAddr.SockAddr) s := ip.NetIP().String() ips = append(ips, s) } return strings.Join(ips, " "), nil } // GetPublicIP returns a string with a single IP address that is NOT part of RFC // 6890 and has a default route. If the system can't determine its IP address // or find a non RFC 6890 IP address, an empty string will be returned instead. // This function is the `eval` equivalent of: // // ``` // $ sockaddr eval -r '{{GetPublicInterfaces | attr "address"}}' /// ``` func GetPublicIP() (string, error) { publicIfs, err := GetPublicInterfaces() if err != nil { return "", err } else if len(publicIfs) < 1 { return "", nil } ifAddr := publicIfs[0] ip := *ToIPAddr(ifAddr.SockAddr) return ip.NetIP().String(), nil } // GetPublicIPs returns a string with all IP addresses that are NOT part of RFC // 6890 (regardless of whether or not there is a default route, unlike // GetPublicIP). If the system can't find any non RFC 6890 IP addresses, an // empty string will be returned instead. This function is the `eval` // equivalent of: // // ``` // $ sockaddr eval -r '{{GetAllInterfaces | exclude "RFC" "6890" | join "address" " "}}' /// ``` func GetPublicIPs() (string, error) { ifAddrs, err := GetAllInterfaces() if err != nil { return "", err } else if len(ifAddrs) < 1 { return "", nil } ifAddrs, _ = FilterIfByType(ifAddrs, TypeIP) if len(ifAddrs) == 0 { return "", nil } OrderedIfAddrBy(AscIfType, AscIfNetworkSize).Sort(ifAddrs) _, ifAddrs, err = IfByRFC("6890", ifAddrs) if err != nil { return "", err } else if len(ifAddrs) == 0 { return "", nil } ips := make([]string, 0, len(ifAddrs)) for _, ifAddr := range ifAddrs { ip := *ToIPAddr(ifAddr.SockAddr) s := ip.NetIP().String() ips = append(ips, s) } return strings.Join(ips, " "), nil } // GetInterfaceIP returns a string with a single IP address sorted by the size // of the network (i.e. IP addresses with a smaller netmask, larger network // size, are sorted first). This function is the `eval` equivalent of: // // ``` // $ 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 { return "", err } ifAddrs, _, err = IfByName(namedIfRE, ifAddrs) if err != nil { return "", err } ifAddrs, _, err = IfByFlag("forwardable", ifAddrs) if err != nil { return "", err } ifAddrs, err = SortIfBy("+type,+size", ifAddrs) if err != nil { return "", err } if len(ifAddrs) == 0 { return "", err } ip := ToIPAddr(ifAddrs[0].SockAddr) if ip == nil { return "", err } return IPAddrAttr(*ip, "address"), nil } // GetInterfaceIPs returns a string with all IPs, sorted by the size of the // network (i.e. IP addresses with a smaller netmask, larger network size, are // sorted first), on a named interface. This function is the `eval` equivalent // of: // // ``` // $ sockaddr eval -r '{{GetAllInterfaces | include "name" <> | sort "type,size" | join "address" " "}}' /// ``` func GetInterfaceIPs(namedIfRE string) (string, error) { ifAddrs, err := GetAllInterfaces() if err != nil { return "", err } ifAddrs, _, err = IfByName(namedIfRE, ifAddrs) if err != nil { return "", err } ifAddrs, err = SortIfBy("+type,+size", ifAddrs) if err != nil { return "", err } if len(ifAddrs) == 0 { return "", err } ips := make([]string, 0, len(ifAddrs)) for _, ifAddr := range ifAddrs { ip := *ToIPAddr(ifAddr.SockAddr) s := ip.NetIP().String() ips = append(ips, s) } return strings.Join(ips, " "), nil } // IfAddrAttrs returns a list of attributes supported by the IfAddr type func IfAddrAttrs() []AttrName { return ifAddrAttrs } // IfAddrAttr returns a string representation of an attribute for the given // IfAddr. func IfAddrAttr(ifAddr IfAddr, attrName AttrName) string { fn, found := ifAddrAttrMap[attrName] if !found { return "" } return fn(ifAddr) } // ifAddrAttrInit is called once at init() func ifAddrAttrInit() { // Sorted for human readability ifAddrAttrs = []AttrName{ "flags", "name", } ifAddrAttrMap = map[AttrName]func(ifAddr IfAddr) string{ "flags": func(ifAddr IfAddr) string { return ifAddr.Interface.Flags.String() }, "name": func(ifAddr IfAddr) string { return ifAddr.Interface.Name }, } } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ifaddrs.go ================================================ package sockaddr import ( "encoding/binary" "errors" "fmt" "math/big" "net" "regexp" "sort" "strconv" "strings" ) var ( // Centralize all regexps and regexp.Copy() where necessary. signRE *regexp.Regexp = regexp.MustCompile(`^[\s]*[+-]`) whitespaceRE *regexp.Regexp = regexp.MustCompile(`[\s]+`) // These regular expressions enable the deprecated parseDefaultIfNameWindows // and should be removed when those functions are. ifNameRE *regexp.Regexp = regexp.MustCompile(`^(?:Ethernet|Wireless LAN) adapter ([^:]+):`) ipAddrRE *regexp.Regexp = regexp.MustCompile(`^ IPv[46] Address\. \. \. \. \. \. \. \. \. \. \. : ([^\s]+)`) ) // IfAddrs is a slice of IfAddr type IfAddrs []IfAddr func (ifs IfAddrs) Len() int { return len(ifs) } // CmpIfFunc is the function signature that must be met to be used in the // OrderedIfAddrBy multiIfAddrSorter type CmpIfAddrFunc func(p1, p2 *IfAddr) int // multiIfAddrSorter implements the Sort interface, sorting the IfAddrs within. type multiIfAddrSorter struct { ifAddrs IfAddrs cmp []CmpIfAddrFunc } // Sort sorts the argument slice according to the Cmp functions passed to // OrderedIfAddrBy. func (ms *multiIfAddrSorter) Sort(ifAddrs IfAddrs) { ms.ifAddrs = ifAddrs sort.Sort(ms) } // OrderedIfAddrBy sorts SockAddr by the list of sort function pointers. func OrderedIfAddrBy(cmpFuncs ...CmpIfAddrFunc) *multiIfAddrSorter { return &multiIfAddrSorter{ cmp: cmpFuncs, } } // Len is part of sort.Interface. func (ms *multiIfAddrSorter) Len() int { return len(ms.ifAddrs) } // Less is part of sort.Interface. It is implemented by looping along the Cmp() // functions until it finds a comparison that is either less than or greater // than. A return value of 0 defers sorting to the next function in the // multisorter (which means the results of sorting may leave the resutls in a // non-deterministic order). func (ms *multiIfAddrSorter) Less(i, j int) bool { p, q := &ms.ifAddrs[i], &ms.ifAddrs[j] // Try all but the last comparison. var k int for k = 0; k < len(ms.cmp)-1; k++ { cmp := ms.cmp[k] x := cmp(p, q) switch x { case -1: // p < q, so we have a decision. return true case 1: // p > q, so we have a decision. return false } // p == q; try the next comparison. } // All comparisons to here said "equal", so just return whatever the // final comparison reports. switch ms.cmp[k](p, q) { case -1: return true case 1: return false default: // Still a tie! Now what? return false panic("undefined sort order for remaining items in the list") } } // Swap is part of sort.Interface. func (ms *multiIfAddrSorter) Swap(i, j int) { ms.ifAddrs[i], ms.ifAddrs[j] = ms.ifAddrs[j], ms.ifAddrs[i] } // AscIfAddress is a sorting function to sort IfAddrs by their respective // address type. Non-equal types are deferred in the sort. func AscIfAddress(p1Ptr, p2Ptr *IfAddr) int { return AscAddress(&p1Ptr.SockAddr, &p2Ptr.SockAddr) } // AscIfDefault is a sorting function to sort IfAddrs by whether or not they // have a default route or not. Non-equal types are deferred in the sort. // // FIXME: This is a particularly expensive sorting operation because of the // non-memoized calls to NewRouteInfo(). In an ideal world the routeInfo data // once at the start of the sort and pass it along as a context or by wrapping // the IfAddr type with this information (this would also solve the inability to // return errors and the possibility of failing silently). Fortunately, // N*log(N) where N = 3 is only ~6.2 invocations. Not ideal, but not worth // optimizing today. The common case is this gets called once or twice. // Patches welcome. func AscIfDefault(p1Ptr, p2Ptr *IfAddr) int { ri, err := NewRouteInfo() if err != nil { return sortDeferDecision } defaultIfName, err := ri.GetDefaultInterfaceName() if err != nil { return sortDeferDecision } switch { case p1Ptr.Interface.Name == defaultIfName && p2Ptr.Interface.Name == defaultIfName: return sortDeferDecision case p1Ptr.Interface.Name == defaultIfName: return sortReceiverBeforeArg case p2Ptr.Interface.Name == defaultIfName: return sortArgBeforeReceiver default: return sortDeferDecision } } // AscIfName is a sorting function to sort IfAddrs by their interface names. func AscIfName(p1Ptr, p2Ptr *IfAddr) int { return strings.Compare(p1Ptr.Name, p2Ptr.Name) } // AscIfNetworkSize is a sorting function to sort IfAddrs by their respective // network mask size. func AscIfNetworkSize(p1Ptr, p2Ptr *IfAddr) int { return AscNetworkSize(&p1Ptr.SockAddr, &p2Ptr.SockAddr) } // AscIfPort is a sorting function to sort IfAddrs by their respective // port type. Non-equal types are deferred in the sort. func AscIfPort(p1Ptr, p2Ptr *IfAddr) int { return AscPort(&p1Ptr.SockAddr, &p2Ptr.SockAddr) } // AscIfPrivate is a sorting function to sort IfAddrs by "private" values before // "public" values. Both IPv4 and IPv6 are compared against RFC6890 (RFC6890 // includes, and is not limited to, RFC1918 and RFC6598 for IPv4, and IPv6 // includes RFC4193). func AscIfPrivate(p1Ptr, p2Ptr *IfAddr) int { return AscPrivate(&p1Ptr.SockAddr, &p2Ptr.SockAddr) } // AscIfType is a sorting function to sort IfAddrs by their respective address // type. Non-equal types are deferred in the sort. func AscIfType(p1Ptr, p2Ptr *IfAddr) int { return AscType(&p1Ptr.SockAddr, &p2Ptr.SockAddr) } // DescIfAddress is identical to AscIfAddress but reverse ordered. func DescIfAddress(p1Ptr, p2Ptr *IfAddr) int { return -1 * AscAddress(&p1Ptr.SockAddr, &p2Ptr.SockAddr) } // DescIfDefault is identical to AscIfDefault but reverse ordered. func DescIfDefault(p1Ptr, p2Ptr *IfAddr) int { return -1 * AscIfDefault(p1Ptr, p2Ptr) } // DescIfName is identical to AscIfName but reverse ordered. func DescIfName(p1Ptr, p2Ptr *IfAddr) int { return -1 * strings.Compare(p1Ptr.Name, p2Ptr.Name) } // DescIfNetworkSize is identical to AscIfNetworkSize but reverse ordered. func DescIfNetworkSize(p1Ptr, p2Ptr *IfAddr) int { return -1 * AscNetworkSize(&p1Ptr.SockAddr, &p2Ptr.SockAddr) } // DescIfPort is identical to AscIfPort but reverse ordered. func DescIfPort(p1Ptr, p2Ptr *IfAddr) int { return -1 * AscPort(&p1Ptr.SockAddr, &p2Ptr.SockAddr) } // DescIfPrivate is identical to AscIfPrivate but reverse ordered. func DescIfPrivate(p1Ptr, p2Ptr *IfAddr) int { return -1 * AscPrivate(&p1Ptr.SockAddr, &p2Ptr.SockAddr) } // DescIfType is identical to AscIfType but reverse ordered. func DescIfType(p1Ptr, p2Ptr *IfAddr) int { return -1 * AscType(&p1Ptr.SockAddr, &p2Ptr.SockAddr) } // FilterIfByType filters IfAddrs and returns a list of the matching type func FilterIfByType(ifAddrs IfAddrs, type_ SockAddrType) (matchedIfs, excludedIfs IfAddrs) { excludedIfs = make(IfAddrs, 0, len(ifAddrs)) matchedIfs = make(IfAddrs, 0, len(ifAddrs)) for _, ifAddr := range ifAddrs { if ifAddr.SockAddr.Type()&type_ != 0 { matchedIfs = append(matchedIfs, ifAddr) } else { excludedIfs = append(excludedIfs, ifAddr) } } return matchedIfs, excludedIfs } // IfAttr forwards the selector to IfAttr.Attr() for resolution. If there is // more than one IfAddr, only the first IfAddr is used. func IfAttr(selectorName string, ifAddr IfAddr) (string, error) { attrName := AttrName(strings.ToLower(selectorName)) attrVal, err := ifAddr.Attr(attrName) return attrVal, err } // IfAttrs forwards the selector to IfAttrs.Attr() for resolution. If there is // more than one IfAddr, only the first IfAddr is used. func IfAttrs(selectorName string, ifAddrs IfAddrs) (string, error) { if len(ifAddrs) == 0 { return "", nil } attrName := AttrName(strings.ToLower(selectorName)) attrVal, err := ifAddrs[0].Attr(attrName) return attrVal, err } // GetAllInterfaces iterates over all available network interfaces and finds all // available IP addresses on each interface and converts them to // sockaddr.IPAddrs, and returning the result as an array of IfAddr. func GetAllInterfaces() (IfAddrs, error) { ifs, err := net.Interfaces() if err != nil { return nil, err } ifAddrs := make(IfAddrs, 0, len(ifs)) for _, intf := range ifs { addrs, err := intf.Addrs() if err != nil { return nil, err } for _, addr := range addrs { var ipAddr IPAddr ipAddr, err = NewIPAddr(addr.String()) if err != nil { return IfAddrs{}, fmt.Errorf("unable to create an IP address from %q", addr.String()) } ifAddr := IfAddr{ SockAddr: ipAddr, Interface: intf, } ifAddrs = append(ifAddrs, ifAddr) } } return ifAddrs, nil } // GetDefaultInterfaces returns IfAddrs of the addresses attached to the default // route. func GetDefaultInterfaces() (IfAddrs, error) { ri, err := NewRouteInfo() if err != nil { return nil, err } defaultIfName, err := ri.GetDefaultInterfaceName() if err != nil { return nil, err } var defaultIfs, ifAddrs IfAddrs ifAddrs, err = GetAllInterfaces() for _, ifAddr := range ifAddrs { if ifAddr.Name == defaultIfName { defaultIfs = append(defaultIfs, ifAddr) } } return defaultIfs, nil } // GetPrivateInterfaces returns an IfAddrs that are part of RFC 6890 and have a // default route. If the system can't determine its IP address or find an RFC // 6890 IP address, an empty IfAddrs will be returned instead. This function is // the `eval` equivalent of: // // ``` // $ 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 { return IfAddrs{}, err } if len(privateIfs) == 0 { return IfAddrs{}, nil } privateIfs, _ = FilterIfByType(privateIfs, TypeIP) if len(privateIfs) == 0 { return IfAddrs{}, nil } privateIfs, _, err = IfByFlag("forwardable", privateIfs) if err != nil { return IfAddrs{}, err } privateIfs, _, err = IfByFlag("up", privateIfs) if err != nil { return IfAddrs{}, err } if len(privateIfs) == 0 { return IfAddrs{}, nil } OrderedIfAddrBy(AscIfDefault, AscIfType, AscIfNetworkSize).Sort(privateIfs) privateIfs, _, err = IfByRFC("6890", privateIfs) if err != nil { return IfAddrs{}, err } else if len(privateIfs) == 0 { return IfAddrs{}, nil } return privateIfs, nil } // GetPublicInterfaces returns an IfAddrs that are NOT part of RFC 6890 and has a // default route. If the system can't determine its IP address or find a non // RFC 6890 IP address, an empty IfAddrs will be returned instead. This // function is the `eval` equivalent of: // // ``` // $ 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 { return IfAddrs{}, err } if len(publicIfs) == 0 { return IfAddrs{}, nil } publicIfs, _ = FilterIfByType(publicIfs, TypeIP) if len(publicIfs) == 0 { return IfAddrs{}, nil } publicIfs, _, err = IfByFlag("forwardable", publicIfs) if err != nil { return IfAddrs{}, err } publicIfs, _, err = IfByFlag("up", publicIfs) if err != nil { return IfAddrs{}, err } if len(publicIfs) == 0 { return IfAddrs{}, nil } OrderedIfAddrBy(AscIfDefault, AscIfType, AscIfNetworkSize).Sort(publicIfs) _, publicIfs, err = IfByRFC("6890", publicIfs) if err != nil { return IfAddrs{}, err } else if len(publicIfs) == 0 { return IfAddrs{}, nil } return publicIfs, nil } // IfByAddress returns a list of matched and non-matched IfAddrs, or an error if // the regexp fails to compile. func IfByAddress(inputRe string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) { re, err := regexp.Compile(inputRe) if err != nil { return nil, nil, fmt.Errorf("Unable to compile address regexp %+q: %v", inputRe, err) } matchedAddrs := make(IfAddrs, 0, len(ifAddrs)) excludedAddrs := make(IfAddrs, 0, len(ifAddrs)) for _, addr := range ifAddrs { if re.MatchString(addr.SockAddr.String()) { matchedAddrs = append(matchedAddrs, addr) } else { excludedAddrs = append(excludedAddrs, addr) } } return matchedAddrs, excludedAddrs, nil } // IfByName returns a list of matched and non-matched IfAddrs, or an error if // the regexp fails to compile. func IfByName(inputRe string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) { re, err := regexp.Compile(inputRe) if err != nil { return nil, nil, fmt.Errorf("Unable to compile name regexp %+q: %v", inputRe, err) } matchedAddrs := make(IfAddrs, 0, len(ifAddrs)) excludedAddrs := make(IfAddrs, 0, len(ifAddrs)) for _, addr := range ifAddrs { if re.MatchString(addr.Name) { matchedAddrs = append(matchedAddrs, addr) } else { excludedAddrs = append(excludedAddrs, addr) } } return matchedAddrs, excludedAddrs, nil } // IfByPort returns a list of matched and non-matched IfAddrs, or an error if // the regexp fails to compile. func IfByPort(inputRe string, ifAddrs IfAddrs) (matchedIfs, excludedIfs IfAddrs, err error) { re, err := regexp.Compile(inputRe) if err != nil { return nil, nil, fmt.Errorf("Unable to compile port regexp %+q: %v", inputRe, err) } ipIfs, nonIfs := FilterIfByType(ifAddrs, TypeIP) matchedIfs = make(IfAddrs, 0, len(ipIfs)) excludedIfs = append(IfAddrs(nil), nonIfs...) for _, addr := range ipIfs { ipAddr := ToIPAddr(addr.SockAddr) if ipAddr == nil { continue } port := strconv.FormatInt(int64((*ipAddr).IPPort()), 10) if re.MatchString(port) { matchedIfs = append(matchedIfs, addr) } else { excludedIfs = append(excludedIfs, addr) } } return matchedIfs, excludedIfs, nil } // IfByRFC returns a list of matched and non-matched IfAddrs that contain the // relevant RFC-specified traits. func IfByRFC(selectorParam string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) { inputRFC, err := strconv.ParseUint(selectorParam, 10, 64) if err != nil { return IfAddrs{}, IfAddrs{}, fmt.Errorf("unable to parse RFC number %q: %v", selectorParam, err) } matchedIfAddrs := make(IfAddrs, 0, len(ifAddrs)) remainingIfAddrs := make(IfAddrs, 0, len(ifAddrs)) rfcNetMap := KnownRFCs() rfcNets, ok := rfcNetMap[uint(inputRFC)] if !ok { return nil, nil, fmt.Errorf("unsupported RFC %d", inputRFC) } for _, ifAddr := range ifAddrs { var contained bool for _, rfcNet := range rfcNets { if rfcNet.Contains(ifAddr.SockAddr) { matchedIfAddrs = append(matchedIfAddrs, ifAddr) contained = true break } } if !contained { remainingIfAddrs = append(remainingIfAddrs, ifAddr) } } return matchedIfAddrs, remainingIfAddrs, nil } // IfByRFCs returns a list of matched and non-matched IfAddrs that contain the // relevant RFC-specified traits. Multiple RFCs can be specified and separated // by the `|` symbol. No protection is taken to ensure an IfAddr does not end // up in both the included and excluded list. func IfByRFCs(selectorParam string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) { var includedIfs, excludedIfs IfAddrs for _, rfcStr := range strings.Split(selectorParam, "|") { includedRFCIfs, excludedRFCIfs, err := IfByRFC(rfcStr, ifAddrs) if err != nil { return IfAddrs{}, IfAddrs{}, fmt.Errorf("unable to lookup RFC number %q: %v", rfcStr, err) } includedIfs = append(includedIfs, includedRFCIfs...) excludedIfs = append(excludedIfs, excludedRFCIfs...) } return includedIfs, excludedIfs, nil } // IfByMaskSize returns a list of matched and non-matched IfAddrs that have the // matching mask size. func IfByMaskSize(selectorParam string, ifAddrs IfAddrs) (matchedIfs, excludedIfs IfAddrs, err error) { maskSize, err := strconv.ParseUint(selectorParam, 10, 64) if err != nil { return IfAddrs{}, IfAddrs{}, fmt.Errorf("invalid exclude size argument (%q): %v", selectorParam, err) } ipIfs, nonIfs := FilterIfByType(ifAddrs, TypeIP) matchedIfs = make(IfAddrs, 0, len(ipIfs)) excludedIfs = append(IfAddrs(nil), nonIfs...) for _, addr := range ipIfs { ipAddr := ToIPAddr(addr.SockAddr) if ipAddr == nil { return IfAddrs{}, IfAddrs{}, fmt.Errorf("unable to filter mask sizes on non-IP type %s: %v", addr.SockAddr.Type().String(), addr.SockAddr.String()) } switch { case (*ipAddr).Type()&TypeIPv4 != 0 && maskSize > 32: return IfAddrs{}, IfAddrs{}, fmt.Errorf("mask size out of bounds for IPv4 address: %d", maskSize) case (*ipAddr).Type()&TypeIPv6 != 0 && maskSize > 128: return IfAddrs{}, IfAddrs{}, fmt.Errorf("mask size out of bounds for IPv6 address: %d", maskSize) } if (*ipAddr).Maskbits() == int(maskSize) { matchedIfs = append(matchedIfs, addr) } else { excludedIfs = append(excludedIfs, addr) } } return matchedIfs, excludedIfs, nil } // IfByType returns a list of matching and non-matching IfAddr that match the // specified type. For instance: // // include "type" "IPv4,IPv6" // // will include any IfAddrs that is either an IPv4 or IPv6 address. Any // addresses on those interfaces that don't match will be included in the // remainder results. func IfByType(inputTypes string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) { matchingIfAddrs := make(IfAddrs, 0, len(ifAddrs)) remainingIfAddrs := make(IfAddrs, 0, len(ifAddrs)) ifTypes := strings.Split(strings.ToLower(inputTypes), "|") for _, ifType := range ifTypes { switch ifType { case "ip", "ipv4", "ipv6", "unix": // Valid types default: return nil, nil, fmt.Errorf("unsupported type %q %q", ifType, inputTypes) } } for _, ifAddr := range ifAddrs { for _, ifType := range ifTypes { var matched bool switch { case ifType == "ip" && ifAddr.SockAddr.Type()&TypeIP != 0: matched = true case ifType == "ipv4" && ifAddr.SockAddr.Type()&TypeIPv4 != 0: matched = true case ifType == "ipv6" && ifAddr.SockAddr.Type()&TypeIPv6 != 0: matched = true case ifType == "unix" && ifAddr.SockAddr.Type()&TypeUnix != 0: matched = true } if matched { matchingIfAddrs = append(matchingIfAddrs, ifAddr) } else { remainingIfAddrs = append(remainingIfAddrs, ifAddr) } } } return matchingIfAddrs, remainingIfAddrs, nil } // IfByFlag returns a list of matching and non-matching IfAddrs that match the // specified type. For instance: // // include "flag" "up,broadcast" // // will include any IfAddrs that have both the "up" and "broadcast" flags set. // Any addresses on those interfaces that don't match will be omitted from the // results. func IfByFlag(inputFlags string, ifAddrs IfAddrs) (matched, remainder IfAddrs, err error) { matchedAddrs := make(IfAddrs, 0, len(ifAddrs)) excludedAddrs := make(IfAddrs, 0, len(ifAddrs)) var wantForwardable, wantGlobalUnicast, wantInterfaceLocalMulticast, wantLinkLocalMulticast, wantLinkLocalUnicast, wantLoopback, wantMulticast, wantUnspecified bool var ifFlags net.Flags var checkFlags, checkAttrs bool for _, flagName := range strings.Split(strings.ToLower(inputFlags), "|") { switch flagName { case "broadcast": checkFlags = true ifFlags = ifFlags | net.FlagBroadcast case "down": checkFlags = true ifFlags = (ifFlags &^ net.FlagUp) case "forwardable": checkAttrs = true wantForwardable = true case "global unicast": checkAttrs = true wantGlobalUnicast = true case "interface-local multicast": checkAttrs = true wantInterfaceLocalMulticast = true case "link-local multicast": checkAttrs = true wantLinkLocalMulticast = true case "link-local unicast": checkAttrs = true wantLinkLocalUnicast = true case "loopback": checkAttrs = true checkFlags = true ifFlags = ifFlags | net.FlagLoopback wantLoopback = true case "multicast": checkAttrs = true checkFlags = true ifFlags = ifFlags | net.FlagMulticast wantMulticast = true case "point-to-point": checkFlags = true ifFlags = ifFlags | net.FlagPointToPoint case "unspecified": checkAttrs = true wantUnspecified = true case "up": checkFlags = true ifFlags = ifFlags | net.FlagUp default: return nil, nil, fmt.Errorf("Unknown interface flag: %+q", flagName) } } for _, ifAddr := range ifAddrs { var matched bool if checkFlags && ifAddr.Interface.Flags&ifFlags == ifFlags { matched = true } if checkAttrs { if ip := ToIPAddr(ifAddr.SockAddr); ip != nil { netIP := (*ip).NetIP() switch { case wantGlobalUnicast && netIP.IsGlobalUnicast(): matched = true case wantInterfaceLocalMulticast && netIP.IsInterfaceLocalMulticast(): matched = true case wantLinkLocalMulticast && netIP.IsLinkLocalMulticast(): matched = true case wantLinkLocalUnicast && netIP.IsLinkLocalUnicast(): matched = true case wantLoopback && netIP.IsLoopback(): matched = true case wantMulticast && netIP.IsMulticast(): matched = true case wantUnspecified && netIP.IsUnspecified(): matched = true case wantForwardable && !IsRFC(ForwardingBlacklist, ifAddr.SockAddr): matched = true } } } if matched { matchedAddrs = append(matchedAddrs, ifAddr) } else { excludedAddrs = append(excludedAddrs, ifAddr) } } return matchedAddrs, excludedAddrs, nil } // IfByNetwork returns an IfAddrs that are equal to or included within the // network passed in by selector. func IfByNetwork(selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, IfAddrs, error) { var includedIfs, excludedIfs IfAddrs for _, netStr := range strings.Split(selectorParam, "|") { netAddr, err := NewIPAddr(netStr) if err != nil { return nil, nil, fmt.Errorf("unable to create an IP address from %+q: %v", netStr, err) } for _, ifAddr := range inputIfAddrs { if netAddr.Contains(ifAddr.SockAddr) { includedIfs = append(includedIfs, ifAddr) } else { excludedIfs = append(excludedIfs, ifAddr) } } } return includedIfs, excludedIfs, nil } // IfAddrMath will return a new IfAddr struct with a mutated value. func IfAddrMath(operation, value string, inputIfAddr IfAddr) (IfAddr, error) { // Regexp used to enforce the sign being a required part of the grammar for // some values. signRe := signRE.Copy() switch strings.ToLower(operation) { case "address": // "address" operates on the IP address and is allowed to overflow or // underflow networks, however it will wrap along the underlying address's // underlying type. if !signRe.MatchString(value) { return IfAddr{}, fmt.Errorf("sign (+/-) is required for operation %q", operation) } switch sockType := inputIfAddr.SockAddr.Type(); sockType { case TypeIPv4: // 33 == Accept any uint32 value // TODO(seanc@): Add the ability to parse hex i, err := strconv.ParseInt(value, 10, 33) if err != nil { return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err) } ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr) ipv4Uint32 := uint32(ipv4.Address) ipv4Uint32 += uint32(i) return IfAddr{ SockAddr: IPv4Addr{ Address: IPv4Address(ipv4Uint32), Mask: ipv4.Mask, }, Interface: inputIfAddr.Interface, }, nil case TypeIPv6: // 64 == Accept any int32 value // TODO(seanc@): Add the ability to parse hex. Also parse a bignum int. i, err := strconv.ParseInt(value, 10, 64) if err != nil { return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err) } ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr) ipv6BigIntA := new(big.Int) ipv6BigIntA.Set(ipv6.Address) ipv6BigIntB := big.NewInt(i) ipv6Addr := ipv6BigIntA.Add(ipv6BigIntA, ipv6BigIntB) ipv6Addr.And(ipv6Addr, ipv6HostMask) return IfAddr{ SockAddr: IPv6Addr{ Address: IPv6Address(ipv6Addr), Mask: ipv6.Mask, }, Interface: inputIfAddr.Interface, }, nil default: return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType) } case "network": // "network" operates on the network address. Positive values start at the // network address and negative values wrap at the network address, which // means a "-1" value on a network will be the broadcast address after // wrapping is applied. if !signRe.MatchString(value) { return IfAddr{}, fmt.Errorf("sign (+/-) is required for operation %q", operation) } switch sockType := inputIfAddr.SockAddr.Type(); sockType { case TypeIPv4: // 33 == Accept any uint32 value // TODO(seanc@): Add the ability to parse hex i, err := strconv.ParseInt(value, 10, 33) if err != nil { return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err) } ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr) ipv4Uint32 := uint32(ipv4.NetworkAddress()) // Wrap along network mask boundaries. EZ-mode wrapping made possible by // use of int64 vs a uint. var wrappedMask int64 if i >= 0 { wrappedMask = i } else { wrappedMask = 1 + i + int64(^uint32(ipv4.Mask)) } ipv4Uint32 = ipv4Uint32 + (uint32(wrappedMask) &^ uint32(ipv4.Mask)) return IfAddr{ SockAddr: IPv4Addr{ Address: IPv4Address(ipv4Uint32), Mask: ipv4.Mask, }, Interface: inputIfAddr.Interface, }, nil case TypeIPv6: // 64 == Accept any int32 value // TODO(seanc@): Add the ability to parse hex. Also parse a bignum int. i, err := strconv.ParseInt(value, 10, 64) if err != nil { return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err) } ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr) ipv6BigInt := new(big.Int) ipv6BigInt.Set(ipv6.NetworkAddress()) mask := new(big.Int) mask.Set(ipv6.Mask) if i > 0 { wrappedMask := new(big.Int) wrappedMask.SetInt64(i) wrappedMask.AndNot(wrappedMask, mask) ipv6BigInt.Add(ipv6BigInt, wrappedMask) } else { // Mask off any bits that exceed the network size. Subtract the // wrappedMask from the last usable - 1 wrappedMask := new(big.Int) wrappedMask.SetInt64(-1 * i) wrappedMask.Sub(wrappedMask, big.NewInt(1)) wrappedMask.AndNot(wrappedMask, mask) lastUsable := new(big.Int) lastUsable.Set(ipv6.LastUsable().(IPv6Addr).Address) ipv6BigInt = lastUsable.Sub(lastUsable, wrappedMask) } return IfAddr{ SockAddr: IPv6Addr{ Address: IPv6Address(ipv6BigInt), Mask: ipv6.Mask, }, Interface: inputIfAddr.Interface, }, nil default: return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType) } case "mask": // "mask" operates on the IP address and returns the IP address on // which the given integer mask has been applied. If the applied mask // corresponds to a larger network than the mask of the IP address, // the latter will be replaced by the former. switch sockType := inputIfAddr.SockAddr.Type(); sockType { case TypeIPv4: i, err := strconv.ParseUint(value, 10, 32) if err != nil { return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err) } if i > 32 { return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv4 addresses must be between 0 and 32", operation) } ipv4 := *ToIPv4Addr(inputIfAddr.SockAddr) ipv4Mask := net.CIDRMask(int(i), 32) ipv4MaskUint32 := binary.BigEndian.Uint32(ipv4Mask) maskedIpv4 := ipv4.NetIP().Mask(ipv4Mask) maskedIpv4Uint32 := binary.BigEndian.Uint32(maskedIpv4) maskedIpv4MaskUint32 := uint32(ipv4.Mask) if ipv4MaskUint32 < maskedIpv4MaskUint32 { maskedIpv4MaskUint32 = ipv4MaskUint32 } return IfAddr{ SockAddr: IPv4Addr{ Address: IPv4Address(maskedIpv4Uint32), Mask: IPv4Mask(maskedIpv4MaskUint32), }, Interface: inputIfAddr.Interface, }, nil case TypeIPv6: i, err := strconv.ParseUint(value, 10, 32) if err != nil { return IfAddr{}, fmt.Errorf("unable to convert %q to int for operation %q: %v", value, operation, err) } if i > 128 { return IfAddr{}, fmt.Errorf("parameter for operation %q on ipv6 addresses must be between 0 and 64", operation) } ipv6 := *ToIPv6Addr(inputIfAddr.SockAddr) ipv6Mask := net.CIDRMask(int(i), 128) ipv6MaskBigInt := new(big.Int) ipv6MaskBigInt.SetBytes(ipv6Mask) maskedIpv6 := ipv6.NetIP().Mask(ipv6Mask) maskedIpv6BigInt := new(big.Int) maskedIpv6BigInt.SetBytes(maskedIpv6) maskedIpv6MaskBigInt := new(big.Int) maskedIpv6MaskBigInt.Set(ipv6.Mask) if ipv6MaskBigInt.Cmp(maskedIpv6MaskBigInt) == -1 { maskedIpv6MaskBigInt = ipv6MaskBigInt } return IfAddr{ SockAddr: IPv6Addr{ Address: IPv6Address(maskedIpv6BigInt), Mask: IPv6Mask(maskedIpv6MaskBigInt), }, Interface: inputIfAddr.Interface, }, nil default: return IfAddr{}, fmt.Errorf("unsupported type for operation %q: %T", operation, sockType) } default: return IfAddr{}, fmt.Errorf("unsupported math operation: %q", operation) } } // IfAddrsMath will apply an IfAddrMath operation each IfAddr struct. Any // failure will result in zero results. func IfAddrsMath(operation, value string, inputIfAddrs IfAddrs) (IfAddrs, error) { outputAddrs := make(IfAddrs, 0, len(inputIfAddrs)) for _, ifAddr := range inputIfAddrs { result, err := IfAddrMath(operation, value, ifAddr) if err != nil { return IfAddrs{}, fmt.Errorf("unable to perform an IPMath operation on %s: %v", ifAddr, err) } outputAddrs = append(outputAddrs, result) } return outputAddrs, nil } // IncludeIfs returns an IfAddrs based on the passed in selector. func IncludeIfs(selectorName, selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) { var includedIfs IfAddrs var err error switch strings.ToLower(selectorName) { case "address": includedIfs, _, err = IfByAddress(selectorParam, inputIfAddrs) case "flag", "flags": includedIfs, _, err = IfByFlag(selectorParam, inputIfAddrs) case "name": includedIfs, _, err = IfByName(selectorParam, inputIfAddrs) case "network": includedIfs, _, err = IfByNetwork(selectorParam, inputIfAddrs) case "port": includedIfs, _, err = IfByPort(selectorParam, inputIfAddrs) case "rfc", "rfcs": includedIfs, _, err = IfByRFCs(selectorParam, inputIfAddrs) case "size": includedIfs, _, err = IfByMaskSize(selectorParam, inputIfAddrs) case "type": includedIfs, _, err = IfByType(selectorParam, inputIfAddrs) default: return IfAddrs{}, fmt.Errorf("invalid include selector %q", selectorName) } if err != nil { return IfAddrs{}, err } return includedIfs, nil } // ExcludeIfs returns an IfAddrs based on the passed in selector. func ExcludeIfs(selectorName, selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) { var excludedIfs IfAddrs var err error switch strings.ToLower(selectorName) { case "address": _, excludedIfs, err = IfByAddress(selectorParam, inputIfAddrs) case "flag", "flags": _, excludedIfs, err = IfByFlag(selectorParam, inputIfAddrs) case "name": _, excludedIfs, err = IfByName(selectorParam, inputIfAddrs) case "network": _, excludedIfs, err = IfByNetwork(selectorParam, inputIfAddrs) case "port": _, excludedIfs, err = IfByPort(selectorParam, inputIfAddrs) case "rfc", "rfcs": _, excludedIfs, err = IfByRFCs(selectorParam, inputIfAddrs) case "size": _, excludedIfs, err = IfByMaskSize(selectorParam, inputIfAddrs) case "type": _, excludedIfs, err = IfByType(selectorParam, inputIfAddrs) default: return IfAddrs{}, fmt.Errorf("invalid exclude selector %q", selectorName) } if err != nil { return IfAddrs{}, err } return excludedIfs, nil } // SortIfBy returns an IfAddrs sorted based on the passed in selector. Multiple // sort clauses can be passed in as a comma delimited list without whitespace. func SortIfBy(selectorParam string, inputIfAddrs IfAddrs) (IfAddrs, error) { sortedIfs := append(IfAddrs(nil), inputIfAddrs...) clauses := strings.Split(selectorParam, ",") sortFuncs := make([]CmpIfAddrFunc, len(clauses)) for i, clause := range clauses { switch strings.TrimSpace(strings.ToLower(clause)) { case "+address", "address": // The "address" selector returns an array of IfAddrs // ordered by the network address. IfAddrs that are not // comparable will be at the end of the list and in a // non-deterministic order. sortFuncs[i] = AscIfAddress case "-address": sortFuncs[i] = DescIfAddress case "+default", "default": sortFuncs[i] = AscIfDefault case "-default": sortFuncs[i] = DescIfDefault case "+name", "name": // The "name" selector returns an array of IfAddrs // ordered by the interface name. sortFuncs[i] = AscIfName case "-name": sortFuncs[i] = DescIfName case "+port", "port": // The "port" selector returns an array of IfAddrs // ordered by the port, if included in the IfAddr. // IfAddrs that are not comparable will be at the end of // the list and in a non-deterministic order. sortFuncs[i] = AscIfPort case "-port": sortFuncs[i] = DescIfPort case "+private", "private": // The "private" selector returns an array of IfAddrs // ordered by private addresses first. IfAddrs that are // not comparable will be at the end of the list and in // a non-deterministic order. sortFuncs[i] = AscIfPrivate case "-private": sortFuncs[i] = DescIfPrivate case "+size", "size": // The "size" selector returns an array of IfAddrs // ordered by the size of the network mask, smaller mask // (larger number of hosts per network) to largest // (e.g. a /24 sorts before a /32). sortFuncs[i] = AscIfNetworkSize case "-size": sortFuncs[i] = DescIfNetworkSize case "+type", "type": // The "type" selector returns an array of IfAddrs // ordered by the type of the IfAddr. The sort order is // Unix, IPv4, then IPv6. sortFuncs[i] = AscIfType case "-type": sortFuncs[i] = DescIfType default: // Return an empty list for invalid sort types. return IfAddrs{}, fmt.Errorf("unknown sort type: %q", clause) } } OrderedIfAddrBy(sortFuncs...).Sort(sortedIfs) return sortedIfs, nil } // UniqueIfAddrsBy creates a unique set of IfAddrs based on the matching // selector. UniqueIfAddrsBy assumes the input has already been sorted. func UniqueIfAddrsBy(selectorName string, inputIfAddrs IfAddrs) (IfAddrs, error) { attrName := strings.ToLower(selectorName) ifs := make(IfAddrs, 0, len(inputIfAddrs)) var lastMatch string for _, ifAddr := range inputIfAddrs { var out string switch attrName { case "address": out = ifAddr.SockAddr.String() case "name": out = ifAddr.Name default: return nil, fmt.Errorf("unsupported unique constraint %+q", selectorName) } switch { case lastMatch == "", lastMatch != out: lastMatch = out ifs = append(ifs, ifAddr) case lastMatch == out: continue } } return ifs, nil } // JoinIfAddrs joins an IfAddrs and returns a string func JoinIfAddrs(selectorName string, joinStr string, inputIfAddrs IfAddrs) (string, error) { outputs := make([]string, 0, len(inputIfAddrs)) attrName := AttrName(strings.ToLower(selectorName)) for _, ifAddr := range inputIfAddrs { var attrVal string var err error attrVal, err = ifAddr.Attr(attrName) if err != nil { return "", err } outputs = append(outputs, attrVal) } return strings.Join(outputs, joinStr), nil } // LimitIfAddrs returns a slice of IfAddrs based on the specified limit. func LimitIfAddrs(lim uint, in IfAddrs) (IfAddrs, error) { // Clamp the limit to the length of the array if int(lim) > len(in) { lim = uint(len(in)) } return in[0:lim], nil } // OffsetIfAddrs returns a slice of IfAddrs based on the specified offset. func OffsetIfAddrs(off int, in IfAddrs) (IfAddrs, error) { var end bool if off < 0 { end = true off = off * -1 } if off > len(in) { return IfAddrs{}, fmt.Errorf("unable to seek past the end of the interface array: offset (%d) exceeds the number of interfaces (%d)", off, len(in)) } if end { return in[len(in)-off:], nil } return in[off:], nil } func (ifAddr IfAddr) String() string { return fmt.Sprintf("%s %v", ifAddr.SockAddr, ifAddr.Interface) } // parseDefaultIfNameFromRoute parses standard route(8)'s output for the *BSDs // and Solaris. func parseDefaultIfNameFromRoute(routeOut string) (string, error) { lines := strings.Split(routeOut, "\n") for _, line := range lines { kvs := strings.SplitN(line, ":", 2) if len(kvs) != 2 { continue } if strings.TrimSpace(kvs[0]) == "interface" { ifName := strings.TrimSpace(kvs[1]) return ifName, nil } } return "", errors.New("No default interface found") } // parseDefaultIfNameFromIPCmd parses the default interface from ip(8) for // Linux. func parseDefaultIfNameFromIPCmd(routeOut string) (string, error) { parsedLines := parseIfNameFromIPCmd(routeOut) for _, parsedLine := range parsedLines { if parsedLine[0] == "default" && parsedLine[1] == "via" && parsedLine[3] == "dev" { ifName := strings.TrimSpace(parsedLine[4]) return ifName, nil } } return "", errors.New("No default interface found") } // parseDefaultIfNameFromIPCmdAndroid parses the default interface from ip(8) for // Android. func parseDefaultIfNameFromIPCmdAndroid(routeOut string) (string, error) { parsedLines := parseIfNameFromIPCmd(routeOut) if len(parsedLines) > 0 { ifName := strings.TrimSpace(parsedLines[0][4]) return ifName, nil } return "", errors.New("No default interface found") } // parseIfNameFromIPCmd parses interfaces from ip(8) for // Linux. func parseIfNameFromIPCmd(routeOut string) [][]string { lines := strings.Split(routeOut, "\n") re := whitespaceRE.Copy() parsedLines := make([][]string, 0, len(lines)) for _, line := range lines { kvs := re.Split(line, -1) if len(kvs) < 5 { continue } parsedLines = append(parsedLines, kvs) } return parsedLines } // parseDefaultIfNameWindows parses the default interface from `netstat -rn` and // `ipconfig` on Windows. // // This has been deprecated in favor of a Powershell-based solution because of // issues with localized Windows versions, but is currently retained for backward // compatibility func parseDefaultIfNameWindows(routeOut, ipconfigOut string) (string, error) { defaultIPAddr, err := parseDefaultIPAddrWindowsRoute(routeOut) if err != nil { return "", err } ifName, err := parseDefaultIfNameWindowsIPConfig(defaultIPAddr, ipconfigOut) if err != nil { return "", err } return ifName, nil } // parseDefaultIPAddrWindowsRoute parses the IP address on the default interface // `netstat -rn`. // // NOTES(sean): Only IPv4 addresses are parsed at this time. If you have an // IPv6 connected host, submit an issue on github.com/hashicorp/go-sockaddr with // the output from `netstat -rn`, `ipconfig`, and version of Windows to see IPv6 // support added. // // This has been deprecated in favor of a Powershell-based solution because of // issues with localized Windows versions, but is currently retained for backward // compatibility. func parseDefaultIPAddrWindowsRoute(routeOut string) (string, error) { lines := strings.Split(routeOut, "\n") re := whitespaceRE.Copy() for _, line := range lines { kvs := re.Split(strings.TrimSpace(line), -1) if len(kvs) < 3 { continue } if kvs[0] == "0.0.0.0" && kvs[1] == "0.0.0.0" { defaultIPAddr := strings.TrimSpace(kvs[3]) return defaultIPAddr, nil } } return "", errors.New("No IP on default interface found") } // parseDefaultIfNameWindowsIPConfig parses the output of `ipconfig` to find the // interface name forwarding traffic to the default gateway. // // This has been deprecated in favor of a Powershell-based solution because of // issues with localized Windows versions, but is currently retained for backward // compatibility func parseDefaultIfNameWindowsIPConfig(defaultIPAddr, routeOut string) (string, error) { lines := strings.Split(routeOut, "\n") ifNameRe := ifNameRE.Copy() ipAddrRe := ipAddrRE.Copy() var ifName string for _, line := range lines { switch ifNameMatches := ifNameRe.FindStringSubmatch(line); { case len(ifNameMatches) > 1: ifName = ifNameMatches[1] continue } switch ipAddrMatches := ipAddrRe.FindStringSubmatch(line); { case len(ipAddrMatches) > 1 && ipAddrMatches[1] == defaultIPAddr: return ifName, nil } } return "", errors.New("No default interface found with matching IP") } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ifattr.go ================================================ package sockaddr import ( "fmt" "net" ) // IfAddr is a union of a SockAddr and a net.Interface. type IfAddr struct { SockAddr net.Interface } // Attr returns the named attribute as a string func (ifAddr IfAddr) Attr(attrName AttrName) (string, error) { val := IfAddrAttr(ifAddr, attrName) if val != "" { return val, nil } return Attr(ifAddr.SockAddr, attrName) } // Attr returns the named attribute as a string func Attr(sa SockAddr, attrName AttrName) (string, error) { switch sockType := sa.Type(); { case sockType&TypeIP != 0: ip := *ToIPAddr(sa) attrVal := IPAddrAttr(ip, attrName) if attrVal != "" { return attrVal, nil } if sockType == TypeIPv4 { ipv4 := *ToIPv4Addr(sa) attrVal := IPv4AddrAttr(ipv4, attrName) if attrVal != "" { return attrVal, nil } } else if sockType == TypeIPv6 { ipv6 := *ToIPv6Addr(sa) attrVal := IPv6AddrAttr(ipv6, attrName) if attrVal != "" { return attrVal, nil } } case sockType == TypeUnix: us := *ToUnixSock(sa) attrVal := UnixSockAttr(us, attrName) if attrVal != "" { return attrVal, nil } } // Non type-specific attributes switch attrName { case "string": return sa.String(), nil case "type": return sa.Type().String(), nil } return "", fmt.Errorf("unsupported attribute name %q", attrName) } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ipaddr.go ================================================ package sockaddr import ( "fmt" "math/big" "net" "strings" ) // Constants for the sizes of IPv3, IPv4, and IPv6 address types. const ( IPv3len = 6 IPv4len = 4 IPv6len = 16 ) // IPAddr is a generic IP address interface for IPv4 and IPv6 addresses, // networks, and socket endpoints. type IPAddr interface { SockAddr AddressBinString() string AddressHexString() string Cmp(SockAddr) int CmpAddress(SockAddr) int CmpPort(SockAddr) int FirstUsable() IPAddr Host() IPAddr IPPort() IPPort LastUsable() IPAddr Maskbits() int NetIP() *net.IP NetIPMask() *net.IPMask NetIPNet() *net.IPNet Network() IPAddr Octets() []int } // IPPort is the type for an IP port number for the TCP and UDP IP transports. type IPPort uint16 // IPPrefixLen is a typed integer representing the prefix length for a given // IPAddr. type IPPrefixLen byte // ipAddrAttrMap is a map of the IPAddr type-specific attributes. var ipAddrAttrMap map[AttrName]func(IPAddr) string var ipAddrAttrs []AttrName func init() { ipAddrInit() } // NewIPAddr creates a new IPAddr from a string. Returns nil if the string is // not an IPv4 or an IPv6 address. func NewIPAddr(addr string) (IPAddr, error) { ipv4Addr, err := NewIPv4Addr(addr) if err == nil { return ipv4Addr, nil } ipv6Addr, err := NewIPv6Addr(addr) if err == nil { return ipv6Addr, nil } return nil, fmt.Errorf("invalid IPAddr %v", addr) } // IPAddrAttr returns a string representation of an attribute for the given // IPAddr. func IPAddrAttr(ip IPAddr, selector AttrName) string { fn, found := ipAddrAttrMap[selector] if !found { return "" } return fn(ip) } // IPAttrs returns a list of attributes supported by the IPAddr type func IPAttrs() []AttrName { return ipAddrAttrs } // MustIPAddr is a helper method that must return an IPAddr or panic on invalid // input. func MustIPAddr(addr string) IPAddr { ip, err := NewIPAddr(addr) if err != nil { panic(fmt.Sprintf("Unable to create an IPAddr from %+q: %v", addr, err)) } return ip } // ipAddrInit is called once at init() func ipAddrInit() { // Sorted for human readability ipAddrAttrs = []AttrName{ "host", "address", "port", "netmask", "network", "mask_bits", "binary", "hex", "first_usable", "last_usable", "octets", } ipAddrAttrMap = map[AttrName]func(ip IPAddr) string{ "address": func(ip IPAddr) string { return ip.NetIP().String() }, "binary": func(ip IPAddr) string { return ip.AddressBinString() }, "first_usable": func(ip IPAddr) string { return ip.FirstUsable().String() }, "hex": func(ip IPAddr) string { return ip.AddressHexString() }, "host": func(ip IPAddr) string { return ip.Host().String() }, "last_usable": func(ip IPAddr) string { return ip.LastUsable().String() }, "mask_bits": func(ip IPAddr) string { return fmt.Sprintf("%d", ip.Maskbits()) }, "netmask": func(ip IPAddr) string { switch v := ip.(type) { case IPv4Addr: ipv4Mask := IPv4Addr{ Address: IPv4Address(v.Mask), Mask: IPv4HostMask, } return ipv4Mask.String() case IPv6Addr: ipv6Mask := new(big.Int) ipv6Mask.Set(v.Mask) ipv6MaskAddr := IPv6Addr{ Address: IPv6Address(ipv6Mask), Mask: ipv6HostMask, } return ipv6MaskAddr.String() default: return fmt.Sprintf("", ip) } }, "network": func(ip IPAddr) string { return ip.Network().NetIP().String() }, "octets": func(ip IPAddr) string { octets := ip.Octets() octetStrs := make([]string, 0, len(octets)) for _, octet := range octets { octetStrs = append(octetStrs, fmt.Sprintf("%d", octet)) } return strings.Join(octetStrs, " ") }, "port": func(ip IPAddr) string { return fmt.Sprintf("%d", ip.IPPort()) }, } } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ipaddrs.go ================================================ package sockaddr import "bytes" type IPAddrs []IPAddr func (s IPAddrs) Len() int { return len(s) } func (s IPAddrs) Swap(i, j int) { s[i], s[j] = s[j], s[i] } // // SortIPAddrsByCmp is a type that satisfies sort.Interface and can be used // // by the routines in this package. The SortIPAddrsByCmp type is used to // // sort IPAddrs by Cmp() // type SortIPAddrsByCmp struct{ IPAddrs } // // Less reports whether the element with index i should sort before the // // element with index j. // func (s SortIPAddrsByCmp) Less(i, j int) bool { // // Sort by Type, then address, then port number. // return Less(s.IPAddrs[i], s.IPAddrs[j]) // } // SortIPAddrsBySpecificMaskLen is a type that satisfies sort.Interface and // can be used by the routines in this package. The // SortIPAddrsBySpecificMaskLen type is used to sort IPAddrs by smallest // network (most specific to largest network). type SortIPAddrsByNetworkSize struct{ IPAddrs } // Less reports whether the element with index i should sort before the // element with index j. func (s SortIPAddrsByNetworkSize) Less(i, j int) bool { // Sort masks with a larger binary value (i.e. fewer hosts per network // prefix) after masks with a smaller value (larger number of hosts per // prefix). switch bytes.Compare([]byte(*s.IPAddrs[i].NetIPMask()), []byte(*s.IPAddrs[j].NetIPMask())) { case 0: // Fall through to the second test if the net.IPMasks are the // same. break case 1: return true case -1: return false default: panic("bad, m'kay?") } // Sort IPs based on the length (i.e. prefer IPv4 over IPv6). iLen := len(*s.IPAddrs[i].NetIP()) jLen := len(*s.IPAddrs[j].NetIP()) if iLen != jLen { return iLen > jLen } // Sort IPs based on their network address from lowest to highest. switch bytes.Compare(s.IPAddrs[i].NetIPNet().IP, s.IPAddrs[j].NetIPNet().IP) { case 0: break case 1: return false case -1: return true default: panic("lol wut?") } // If a host does not have a port set, it always sorts after hosts // that have a port (e.g. a host with a /32 and port number is more // specific and should sort first over a host with a /32 but no port // set). if s.IPAddrs[i].IPPort() == 0 || s.IPAddrs[j].IPPort() == 0 { return false } return s.IPAddrs[i].IPPort() < s.IPAddrs[j].IPPort() } // SortIPAddrsBySpecificMaskLen is a type that satisfies sort.Interface and // can be used by the routines in this package. The // SortIPAddrsBySpecificMaskLen type is used to sort IPAddrs by smallest // network (most specific to largest network). type SortIPAddrsBySpecificMaskLen struct{ IPAddrs } // Less reports whether the element with index i should sort before the // element with index j. func (s SortIPAddrsBySpecificMaskLen) Less(i, j int) bool { return s.IPAddrs[i].Maskbits() > s.IPAddrs[j].Maskbits() } // SortIPAddrsByBroadMaskLen is a type that satisfies sort.Interface and can // be used by the routines in this package. The SortIPAddrsByBroadMaskLen // type is used to sort IPAddrs by largest network (i.e. largest subnets // first). type SortIPAddrsByBroadMaskLen struct{ IPAddrs } // Less reports whether the element with index i should sort before the // element with index j. func (s SortIPAddrsByBroadMaskLen) Less(i, j int) bool { return s.IPAddrs[i].Maskbits() < s.IPAddrs[j].Maskbits() } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/ipv4addr.go ================================================ package sockaddr import ( "encoding/binary" "fmt" "net" "regexp" "strconv" "strings" ) type ( // IPv4Address is a named type representing an IPv4 address. IPv4Address uint32 // IPv4Network is a named type representing an IPv4 network. IPv4Network uint32 // IPv4Mask is a named type representing an IPv4 network mask. IPv4Mask uint32 ) // IPv4HostMask is a constant represents a /32 IPv4 Address // (i.e. 255.255.255.255). const IPv4HostMask = IPv4Mask(0xffffffff) // ipv4AddrAttrMap is a map of the IPv4Addr type-specific attributes. var ipv4AddrAttrMap map[AttrName]func(IPv4Addr) string var ipv4AddrAttrs []AttrName var trailingHexNetmaskRE *regexp.Regexp // IPv4Addr implements a convenience wrapper around the union of Go's // built-in net.IP and net.IPNet types. In UNIX-speak, IPv4Addr implements // `sockaddr` when the the address family is set to AF_INET // (i.e. `sockaddr_in`). type IPv4Addr struct { IPAddr Address IPv4Address Mask IPv4Mask Port IPPort } func init() { ipv4AddrInit() trailingHexNetmaskRE = regexp.MustCompile(`/([0f]{8})$`) } // NewIPv4Addr creates an IPv4Addr from a string. String can be in the form // of either an IPv4:port (e.g. `1.2.3.4:80`, in which case the mask is // assumed to be a `/32`), an IPv4 address (e.g. `1.2.3.4`, also with a `/32` // mask), or an IPv4 CIDR (e.g. `1.2.3.4/24`, which has its IP port // initialized to zero). ipv4Str can not be a hostname. // // NOTE: Many net.*() routines will initialize and return an IPv6 address. // To create uint32 values from net.IP, always test to make sure the address // returned can be converted to a 4 byte array using To4(). func NewIPv4Addr(ipv4Str string) (IPv4Addr, error) { // Strip off any bogus hex-encoded netmasks that will be mis-parsed by Go. In // particular, clients with the Barracuda VPN client will see something like: // `192.168.3.51/00ffffff` as their IP address. trailingHexNetmaskRe := trailingHexNetmaskRE.Copy() if match := trailingHexNetmaskRe.FindStringIndex(ipv4Str); match != nil { ipv4Str = ipv4Str[:match[0]] } // Parse as an IPv4 CIDR ipAddr, network, err := net.ParseCIDR(ipv4Str) if err == nil { ipv4 := ipAddr.To4() if ipv4 == nil { return IPv4Addr{}, fmt.Errorf("Unable to convert %s to an IPv4 address", ipv4Str) } // If we see an IPv6 netmask, convert it to an IPv4 mask. netmaskSepPos := strings.LastIndexByte(ipv4Str, '/') if netmaskSepPos != -1 && netmaskSepPos+1 < len(ipv4Str) { netMask, err := strconv.ParseUint(ipv4Str[netmaskSepPos+1:], 10, 8) if err != nil { return IPv4Addr{}, fmt.Errorf("Unable to convert %s to an IPv4 address: unable to parse CIDR netmask: %v", ipv4Str, err) } else if netMask > 128 { return IPv4Addr{}, fmt.Errorf("Unable to convert %s to an IPv4 address: invalid CIDR netmask", ipv4Str) } if netMask >= 96 { // Convert the IPv6 netmask to an IPv4 netmask network.Mask = net.CIDRMask(int(netMask-96), IPv4len*8) } } ipv4Addr := IPv4Addr{ Address: IPv4Address(binary.BigEndian.Uint32(ipv4)), Mask: IPv4Mask(binary.BigEndian.Uint32(network.Mask)), } return ipv4Addr, nil } // Attempt to parse ipv4Str as a /32 host with a port number. tcpAddr, err := net.ResolveTCPAddr("tcp4", ipv4Str) if err == nil { ipv4 := tcpAddr.IP.To4() if ipv4 == nil { return IPv4Addr{}, fmt.Errorf("Unable to resolve %+q as an IPv4 address", ipv4Str) } ipv4Uint32 := binary.BigEndian.Uint32(ipv4) ipv4Addr := IPv4Addr{ Address: IPv4Address(ipv4Uint32), Mask: IPv4HostMask, Port: IPPort(tcpAddr.Port), } return ipv4Addr, nil } // Parse as a naked IPv4 address ip := net.ParseIP(ipv4Str) if ip != nil { ipv4 := ip.To4() if ipv4 == nil { return IPv4Addr{}, fmt.Errorf("Unable to string convert %+q to an IPv4 address", ipv4Str) } ipv4Uint32 := binary.BigEndian.Uint32(ipv4) ipv4Addr := IPv4Addr{ Address: IPv4Address(ipv4Uint32), Mask: IPv4HostMask, } return ipv4Addr, nil } return IPv4Addr{}, fmt.Errorf("Unable to parse %+q to an IPv4 address: %v", ipv4Str, err) } // AddressBinString returns a string with the IPv4Addr's Address represented // as a sequence of '0' and '1' characters. This method is useful for // debugging or by operators who want to inspect an address. func (ipv4 IPv4Addr) AddressBinString() string { return fmt.Sprintf("%032s", strconv.FormatUint(uint64(ipv4.Address), 2)) } // AddressHexString returns a string with the IPv4Addr address represented as // a sequence of hex characters. This method is useful for debugging or by // operators who want to inspect an address. func (ipv4 IPv4Addr) AddressHexString() string { return fmt.Sprintf("%08s", strconv.FormatUint(uint64(ipv4.Address), 16)) } // Broadcast is an IPv4Addr-only method that returns the broadcast address of // the network. // // NOTE: IPv6 only supports multicast, so this method only exists for // IPv4Addr. func (ipv4 IPv4Addr) Broadcast() IPAddr { // Nothing should listen on a broadcast address. return IPv4Addr{ Address: IPv4Address(ipv4.BroadcastAddress()), Mask: IPv4HostMask, } } // BroadcastAddress returns a IPv4Network of the IPv4Addr's broadcast // address. func (ipv4 IPv4Addr) BroadcastAddress() IPv4Network { return IPv4Network(uint32(ipv4.Address)&uint32(ipv4.Mask) | ^uint32(ipv4.Mask)) } // 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. func (ipv4 IPv4Addr) CmpAddress(sa SockAddr) int { ipv4b, ok := sa.(IPv4Addr) if !ok { return sortDeferDecision } switch { case ipv4.Address == ipv4b.Address: return sortDeferDecision case ipv4.Address < ipv4b.Address: return sortReceiverBeforeArg default: return sortArgBeforeReceiver } } // 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. func (ipv4 IPv4Addr) CmpPort(sa SockAddr) int { var saPort IPPort switch v := sa.(type) { case IPv4Addr: saPort = v.Port case IPv6Addr: saPort = v.Port default: return sortDeferDecision } switch { case ipv4.Port == saPort: return sortDeferDecision case ipv4.Port < saPort: return sortReceiverBeforeArg default: return sortArgBeforeReceiver } } // 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. func (ipv4 IPv4Addr) CmpRFC(rfcNum uint, sa SockAddr) int { recvInRFC := IsRFC(rfcNum, ipv4) ipv4b, ok := sa.(IPv4Addr) if !ok { // If the receiver is part of the desired RFC and the SockAddr // argument is not, return -1 so that the receiver sorts before // the non-IPv4 SockAddr. Conversely, if the receiver is not // part of the RFC, punt on sorting and leave it for the next // sorter. if recvInRFC { return sortReceiverBeforeArg } else { return sortDeferDecision } } argInRFC := IsRFC(rfcNum, ipv4b) switch { case (recvInRFC && argInRFC), (!recvInRFC && !argInRFC): // If a and b both belong to the RFC, or neither belong to // rfcNum, defer sorting to the next sorter. return sortDeferDecision case recvInRFC && !argInRFC: return sortReceiverBeforeArg default: return sortArgBeforeReceiver } } // Contains returns true if the SockAddr is contained within the receiver. func (ipv4 IPv4Addr) Contains(sa SockAddr) bool { ipv4b, ok := sa.(IPv4Addr) if !ok { return false } return ipv4.ContainsNetwork(ipv4b) } // ContainsAddress returns true if the IPv4Address is contained within the // receiver. func (ipv4 IPv4Addr) ContainsAddress(x IPv4Address) bool { return IPv4Address(ipv4.NetworkAddress()) <= x && IPv4Address(ipv4.BroadcastAddress()) >= x } // ContainsNetwork returns true if the network from IPv4Addr is contained // within the receiver. func (ipv4 IPv4Addr) ContainsNetwork(x IPv4Addr) bool { return ipv4.NetworkAddress() <= x.NetworkAddress() && ipv4.BroadcastAddress() >= x.BroadcastAddress() } // DialPacketArgs returns the arguments required to be passed to // net.DialUDP(). If the Mask of ipv4 is not a /32 or the Port is 0, // DialPacketArgs() will fail. See Host() to create an IPv4Addr with its // mask set to /32. func (ipv4 IPv4Addr) DialPacketArgs() (network, dialArgs string) { if ipv4.Mask != IPv4HostMask || ipv4.Port == 0 { return "udp4", "" } return "udp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port) } // DialStreamArgs returns the arguments required to be passed to // net.DialTCP(). If the Mask of ipv4 is not a /32 or the Port is 0, // DialStreamArgs() will fail. See Host() to create an IPv4Addr with its // mask set to /32. func (ipv4 IPv4Addr) DialStreamArgs() (network, dialArgs string) { if ipv4.Mask != IPv4HostMask || ipv4.Port == 0 { return "tcp4", "" } return "tcp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port) } // Equal returns true if a SockAddr is equal to the receiving IPv4Addr. func (ipv4 IPv4Addr) Equal(sa SockAddr) bool { ipv4b, ok := sa.(IPv4Addr) if !ok { return false } if ipv4.Port != ipv4b.Port { return false } if ipv4.Address != ipv4b.Address { return false } if ipv4.NetIPNet().String() != ipv4b.NetIPNet().String() { return false } return true } // FirstUsable returns an IPv4Addr set to the first address following the // network prefix. The first usable address in a network is normally the // gateway and should not be used except by devices forwarding packets // between two administratively distinct networks (i.e. a router). This // function does not discriminate against first usable vs "first address that // should be used." For example, FirstUsable() on "192.168.1.10/24" would // return the address "192.168.1.1/24". func (ipv4 IPv4Addr) FirstUsable() IPAddr { addr := ipv4.NetworkAddress() // If /32, return the address itself. If /31 assume a point-to-point // link and return the lower address. if ipv4.Maskbits() < 31 { addr++ } return IPv4Addr{ Address: IPv4Address(addr), Mask: IPv4HostMask, } } // Host returns a copy of ipv4 with its mask set to /32 so that it can be // used by DialPacketArgs(), DialStreamArgs(), ListenPacketArgs(), or // ListenStreamArgs(). func (ipv4 IPv4Addr) Host() IPAddr { // Nothing should listen on a broadcast address. return IPv4Addr{ Address: ipv4.Address, Mask: IPv4HostMask, Port: ipv4.Port, } } // IPPort returns the Port number attached to the IPv4Addr func (ipv4 IPv4Addr) IPPort() IPPort { return ipv4.Port } // LastUsable returns the last address before the broadcast address in a // given network. func (ipv4 IPv4Addr) LastUsable() IPAddr { addr := ipv4.BroadcastAddress() // If /32, return the address itself. If /31 assume a point-to-point // link and return the upper address. if ipv4.Maskbits() < 31 { addr-- } return IPv4Addr{ Address: IPv4Address(addr), Mask: IPv4HostMask, } } // ListenPacketArgs returns the arguments required to be passed to // net.ListenUDP(). If the Mask of ipv4 is not a /32, ListenPacketArgs() // will fail. See Host() to create an IPv4Addr with its mask set to /32. func (ipv4 IPv4Addr) ListenPacketArgs() (network, listenArgs string) { if ipv4.Mask != IPv4HostMask { return "udp4", "" } return "udp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port) } // ListenStreamArgs returns the arguments required to be passed to // net.ListenTCP(). If the Mask of ipv4 is not a /32, ListenStreamArgs() // will fail. See Host() to create an IPv4Addr with its mask set to /32. func (ipv4 IPv4Addr) ListenStreamArgs() (network, listenArgs string) { if ipv4.Mask != IPv4HostMask { return "tcp4", "" } return "tcp4", fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port) } // Maskbits returns the number of network mask bits in a given IPv4Addr. For // example, the Maskbits() of "192.168.1.1/24" would return 24. func (ipv4 IPv4Addr) Maskbits() int { mask := make(net.IPMask, IPv4len) binary.BigEndian.PutUint32(mask, uint32(ipv4.Mask)) maskOnes, _ := mask.Size() return maskOnes } // MustIPv4Addr is a helper method that must return an IPv4Addr or panic on // invalid input. func MustIPv4Addr(addr string) IPv4Addr { ipv4, err := NewIPv4Addr(addr) if err != nil { panic(fmt.Sprintf("Unable to create an IPv4Addr from %+q: %v", addr, err)) } return ipv4 } // NetIP returns the address as a net.IP (address is always presized to // IPv4). func (ipv4 IPv4Addr) NetIP() *net.IP { x := make(net.IP, IPv4len) binary.BigEndian.PutUint32(x, uint32(ipv4.Address)) return &x } // NetIPMask create a new net.IPMask from the IPv4Addr. func (ipv4 IPv4Addr) NetIPMask() *net.IPMask { ipv4Mask := net.IPMask{} ipv4Mask = make(net.IPMask, IPv4len) binary.BigEndian.PutUint32(ipv4Mask, uint32(ipv4.Mask)) return &ipv4Mask } // NetIPNet create a new net.IPNet from the IPv4Addr. func (ipv4 IPv4Addr) NetIPNet() *net.IPNet { ipv4net := &net.IPNet{} ipv4net.IP = make(net.IP, IPv4len) binary.BigEndian.PutUint32(ipv4net.IP, uint32(ipv4.NetworkAddress())) ipv4net.Mask = *ipv4.NetIPMask() return ipv4net } // Network returns the network prefix or network address for a given network. func (ipv4 IPv4Addr) Network() IPAddr { return IPv4Addr{ Address: IPv4Address(ipv4.NetworkAddress()), Mask: ipv4.Mask, } } // NetworkAddress returns an IPv4Network of the IPv4Addr's network address. func (ipv4 IPv4Addr) NetworkAddress() IPv4Network { return IPv4Network(uint32(ipv4.Address) & uint32(ipv4.Mask)) } // Octets returns a slice of the four octets in an IPv4Addr's Address. The // order of the bytes is big endian. func (ipv4 IPv4Addr) Octets() []int { return []int{ int(ipv4.Address >> 24), int((ipv4.Address >> 16) & 0xff), int((ipv4.Address >> 8) & 0xff), int(ipv4.Address & 0xff), } } // String returns a string representation of the IPv4Addr func (ipv4 IPv4Addr) String() string { if ipv4.Port != 0 { return fmt.Sprintf("%s:%d", ipv4.NetIP().String(), ipv4.Port) } if ipv4.Maskbits() == 32 { return ipv4.NetIP().String() } return fmt.Sprintf("%s/%d", ipv4.NetIP().String(), ipv4.Maskbits()) } // Type is used as a type switch and returns TypeIPv4 func (IPv4Addr) Type() SockAddrType { return TypeIPv4 } // IPv4AddrAttr returns a string representation of an attribute for the given // IPv4Addr. func IPv4AddrAttr(ipv4 IPv4Addr, selector AttrName) string { fn, found := ipv4AddrAttrMap[selector] if !found { return "" } return fn(ipv4) } // IPv4Attrs returns a list of attributes supported by the IPv4Addr type func IPv4Attrs() []AttrName { return ipv4AddrAttrs } // ipv4AddrInit is called once at init() func ipv4AddrInit() { // Sorted for human readability ipv4AddrAttrs = []AttrName{ "size", // Same position as in IPv6 for output consistency "broadcast", "uint32", } ipv4AddrAttrMap = map[AttrName]func(ipv4 IPv4Addr) string{ "broadcast": func(ipv4 IPv4Addr) string { return ipv4.Broadcast().String() }, "size": func(ipv4 IPv4Addr) string { return fmt.Sprintf("%d", 1< 2 && ipv6Str[0] == '[' && ipv6Str[len(ipv6Str)-1] == ']' { ipv6Str = ipv6Str[1 : len(ipv6Str)-1] } ip := net.ParseIP(ipv6Str) if ip != nil { ipv6 := ip.To16() if ipv6 == nil { return IPv6Addr{}, fmt.Errorf("Unable to string convert %+q to a 16byte IPv6 address", ipv6Str) } ipv6BigIntAddr := new(big.Int) ipv6BigIntAddr.SetBytes(ipv6) ipv6BigIntMask := new(big.Int) ipv6BigIntMask.Set(ipv6HostMask) return IPv6Addr{ Address: IPv6Address(ipv6BigIntAddr), Mask: IPv6Mask(ipv6BigIntMask), }, nil } // Parse as an IPv6 CIDR ipAddr, network, err := net.ParseCIDR(ipv6Str) if err == nil { ipv6 := ipAddr.To16() if ipv6 == nil { return IPv6Addr{}, fmt.Errorf("Unable to convert %+q to a 16byte IPv6 address", ipv6Str) } ipv6BigIntAddr := new(big.Int) ipv6BigIntAddr.SetBytes(ipv6) ipv6BigIntMask := new(big.Int) ipv6BigIntMask.SetBytes(network.Mask) ipv6Addr := IPv6Addr{ Address: IPv6Address(ipv6BigIntAddr), Mask: IPv6Mask(ipv6BigIntMask), } return ipv6Addr, nil } return IPv6Addr{}, fmt.Errorf("Unable to parse %+q to an IPv6 address: %v", ipv6Str, err) } // AddressBinString returns a string with the IPv6Addr's Address represented // as a sequence of '0' and '1' characters. This method is useful for // debugging or by operators who want to inspect an address. func (ipv6 IPv6Addr) AddressBinString() string { bi := big.Int(*ipv6.Address) return fmt.Sprintf("%0128s", bi.Text(2)) } // AddressHexString returns a string with the IPv6Addr address represented as // a sequence of hex characters. This method is useful for debugging or by // operators who want to inspect an address. func (ipv6 IPv6Addr) AddressHexString() string { bi := big.Int(*ipv6.Address) return fmt.Sprintf("%032s", bi.Text(16)) } // 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. func (ipv6 IPv6Addr) CmpAddress(sa SockAddr) int { ipv6b, ok := sa.(IPv6Addr) if !ok { return sortDeferDecision } ipv6aBigInt := new(big.Int) ipv6aBigInt.Set(ipv6.Address) ipv6bBigInt := new(big.Int) ipv6bBigInt.Set(ipv6b.Address) return ipv6aBigInt.Cmp(ipv6bBigInt) } // 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. func (ipv6 IPv6Addr) CmpPort(sa SockAddr) int { var saPort IPPort switch v := sa.(type) { case IPv4Addr: saPort = v.Port case IPv6Addr: saPort = v.Port default: return sortDeferDecision } switch { case ipv6.Port == saPort: return sortDeferDecision case ipv6.Port < saPort: return sortReceiverBeforeArg default: return sortArgBeforeReceiver } } // 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. func (ipv6 IPv6Addr) CmpRFC(rfcNum uint, sa SockAddr) int { recvInRFC := IsRFC(rfcNum, ipv6) ipv6b, ok := sa.(IPv6Addr) if !ok { // If the receiver is part of the desired RFC and the SockAddr // argument is not, sort receiver before the non-IPv6 SockAddr. // Conversely, if the receiver is not part of the RFC, punt on // sorting and leave it for the next sorter. if recvInRFC { return sortReceiverBeforeArg } else { return sortDeferDecision } } argInRFC := IsRFC(rfcNum, ipv6b) switch { case (recvInRFC && argInRFC), (!recvInRFC && !argInRFC): // If a and b both belong to the RFC, or neither belong to // rfcNum, defer sorting to the next sorter. return sortDeferDecision case recvInRFC && !argInRFC: return sortReceiverBeforeArg default: return sortArgBeforeReceiver } } // Contains returns true if the SockAddr is contained within the receiver. func (ipv6 IPv6Addr) Contains(sa SockAddr) bool { ipv6b, ok := sa.(IPv6Addr) if !ok { return false } return ipv6.ContainsNetwork(ipv6b) } // ContainsAddress returns true if the IPv6Address is contained within the // receiver. func (ipv6 IPv6Addr) ContainsAddress(x IPv6Address) bool { xAddr := IPv6Addr{ Address: x, Mask: ipv6HostMask, } { xIPv6 := xAddr.FirstUsable().(IPv6Addr) yIPv6 := ipv6.FirstUsable().(IPv6Addr) if xIPv6.CmpAddress(yIPv6) >= 1 { return false } } { xIPv6 := xAddr.LastUsable().(IPv6Addr) yIPv6 := ipv6.LastUsable().(IPv6Addr) if xIPv6.CmpAddress(yIPv6) <= -1 { return false } } return true } // ContainsNetwork returns true if the network from IPv6Addr is contained within // the receiver. func (x IPv6Addr) ContainsNetwork(y IPv6Addr) bool { { xIPv6 := x.FirstUsable().(IPv6Addr) yIPv6 := y.FirstUsable().(IPv6Addr) if ret := xIPv6.CmpAddress(yIPv6); ret >= 1 { return false } } { xIPv6 := x.LastUsable().(IPv6Addr) yIPv6 := y.LastUsable().(IPv6Addr) if ret := xIPv6.CmpAddress(yIPv6); ret <= -1 { return false } } return true } // DialPacketArgs returns the arguments required to be passed to // net.DialUDP(). If the Mask of ipv6 is not a /128 or the Port is 0, // DialPacketArgs() will fail. See Host() to create an IPv6Addr with its // mask set to /128. func (ipv6 IPv6Addr) DialPacketArgs() (network, dialArgs string) { ipv6Mask := big.Int(*ipv6.Mask) if ipv6Mask.Cmp(ipv6HostMask) != 0 || ipv6.Port == 0 { return "udp6", "" } return "udp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port) } // DialStreamArgs returns the arguments required to be passed to // net.DialTCP(). If the Mask of ipv6 is not a /128 or the Port is 0, // DialStreamArgs() will fail. See Host() to create an IPv6Addr with its // mask set to /128. func (ipv6 IPv6Addr) DialStreamArgs() (network, dialArgs string) { ipv6Mask := big.Int(*ipv6.Mask) if ipv6Mask.Cmp(ipv6HostMask) != 0 || ipv6.Port == 0 { return "tcp6", "" } return "tcp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port) } // Equal returns true if a SockAddr is equal to the receiving IPv4Addr. func (ipv6a IPv6Addr) Equal(sa SockAddr) bool { ipv6b, ok := sa.(IPv6Addr) if !ok { return false } if ipv6a.NetIP().String() != ipv6b.NetIP().String() { return false } if ipv6a.NetIPNet().String() != ipv6b.NetIPNet().String() { return false } if ipv6a.Port != ipv6b.Port { return false } return true } // FirstUsable returns an IPv6Addr set to the first address following the // network prefix. The first usable address in a network is normally the // gateway and should not be used except by devices forwarding packets // between two administratively distinct networks (i.e. a router). This // function does not discriminate against first usable vs "first address that // should be used." For example, FirstUsable() on "2001:0db8::0003/64" would // return "2001:0db8::00011". func (ipv6 IPv6Addr) FirstUsable() IPAddr { return IPv6Addr{ Address: IPv6Address(ipv6.NetworkAddress()), Mask: ipv6HostMask, } } // Host returns a copy of ipv6 with its mask set to /128 so that it can be // used by DialPacketArgs(), DialStreamArgs(), ListenPacketArgs(), or // ListenStreamArgs(). func (ipv6 IPv6Addr) Host() IPAddr { // Nothing should listen on a broadcast address. return IPv6Addr{ Address: ipv6.Address, Mask: ipv6HostMask, Port: ipv6.Port, } } // IPPort returns the Port number attached to the IPv6Addr func (ipv6 IPv6Addr) IPPort() IPPort { return ipv6.Port } // LastUsable returns the last address in a given network. func (ipv6 IPv6Addr) LastUsable() IPAddr { addr := new(big.Int) addr.Set(ipv6.Address) mask := new(big.Int) mask.Set(ipv6.Mask) negMask := new(big.Int) negMask.Xor(ipv6HostMask, mask) lastAddr := new(big.Int) lastAddr.And(addr, mask) lastAddr.Or(lastAddr, negMask) return IPv6Addr{ Address: IPv6Address(lastAddr), Mask: ipv6HostMask, } } // ListenPacketArgs returns the arguments required to be passed to // net.ListenUDP(). If the Mask of ipv6 is not a /128, ListenPacketArgs() // will fail. See Host() to create an IPv6Addr with its mask set to /128. func (ipv6 IPv6Addr) ListenPacketArgs() (network, listenArgs string) { ipv6Mask := big.Int(*ipv6.Mask) if ipv6Mask.Cmp(ipv6HostMask) != 0 { return "udp6", "" } return "udp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port) } // ListenStreamArgs returns the arguments required to be passed to // net.ListenTCP(). If the Mask of ipv6 is not a /128, ListenStreamArgs() // will fail. See Host() to create an IPv6Addr with its mask set to /128. func (ipv6 IPv6Addr) ListenStreamArgs() (network, listenArgs string) { ipv6Mask := big.Int(*ipv6.Mask) if ipv6Mask.Cmp(ipv6HostMask) != 0 { return "tcp6", "" } return "tcp6", fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port) } // Maskbits returns the number of network mask bits in a given IPv6Addr. For // example, the Maskbits() of "2001:0db8::0003/64" would return 64. func (ipv6 IPv6Addr) Maskbits() int { maskOnes, _ := ipv6.NetIPNet().Mask.Size() return maskOnes } // MustIPv6Addr is a helper method that must return an IPv6Addr or panic on // invalid input. func MustIPv6Addr(addr string) IPv6Addr { ipv6, err := NewIPv6Addr(addr) if err != nil { panic(fmt.Sprintf("Unable to create an IPv6Addr from %+q: %v", addr, err)) } return ipv6 } // NetIP returns the address as a net.IP. func (ipv6 IPv6Addr) NetIP() *net.IP { return bigIntToNetIPv6(ipv6.Address) } // NetIPMask create a new net.IPMask from the IPv6Addr. func (ipv6 IPv6Addr) NetIPMask() *net.IPMask { ipv6Mask := make(net.IPMask, IPv6len) m := big.Int(*ipv6.Mask) copy(ipv6Mask, m.Bytes()) return &ipv6Mask } // Network returns a pointer to the net.IPNet within IPv4Addr receiver. func (ipv6 IPv6Addr) NetIPNet() *net.IPNet { ipv6net := &net.IPNet{} ipv6net.IP = make(net.IP, IPv6len) copy(ipv6net.IP, *ipv6.NetIP()) ipv6net.Mask = *ipv6.NetIPMask() return ipv6net } // Network returns the network prefix or network address for a given network. func (ipv6 IPv6Addr) Network() IPAddr { return IPv6Addr{ Address: IPv6Address(ipv6.NetworkAddress()), Mask: ipv6.Mask, } } // NetworkAddress returns an IPv6Network of the IPv6Addr's network address. func (ipv6 IPv6Addr) NetworkAddress() IPv6Network { addr := new(big.Int) addr.SetBytes((*ipv6.Address).Bytes()) mask := new(big.Int) mask.SetBytes(*ipv6.NetIPMask()) netAddr := new(big.Int) netAddr.And(addr, mask) return IPv6Network(netAddr) } // Octets returns a slice of the 16 octets in an IPv6Addr's Address. The // order of the bytes is big endian. func (ipv6 IPv6Addr) Octets() []int { x := make([]int, IPv6len) for i, b := range *bigIntToNetIPv6(ipv6.Address) { x[i] = int(b) } return x } // String returns a string representation of the IPv6Addr func (ipv6 IPv6Addr) String() string { if ipv6.Port != 0 { return fmt.Sprintf("[%s]:%d", ipv6.NetIP().String(), ipv6.Port) } if ipv6.Maskbits() == 128 { return ipv6.NetIP().String() } return fmt.Sprintf("%s/%d", ipv6.NetIP().String(), ipv6.Maskbits()) } // Type is used as a type switch and returns TypeIPv6 func (IPv6Addr) Type() SockAddrType { return TypeIPv6 } // IPv6Attrs returns a list of attributes supported by the IPv6Addr type func IPv6Attrs() []AttrName { return ipv6AddrAttrs } // IPv6AddrAttr returns a string representation of an attribute for the given // IPv6Addr. func IPv6AddrAttr(ipv6 IPv6Addr, selector AttrName) string { fn, found := ipv6AddrAttrMap[selector] if !found { return "" } return fn(ipv6) } // ipv6AddrInit is called once at init() func ipv6AddrInit() { // Sorted for human readability ipv6AddrAttrs = []AttrName{ "size", // Same position as in IPv6 for output consistency "uint128", } ipv6AddrAttrMap = map[AttrName]func(ipv6 IPv6Addr) string{ "size": func(ipv6 IPv6Addr) string { netSize := big.NewInt(1) netSize = netSize.Lsh(netSize, uint(IPv6len*8-ipv6.Maskbits())) return netSize.Text(10) }, "uint128": func(ipv6 IPv6Addr) string { b := big.Int(*ipv6.Address) return b.Text(10) }, } } // bigIntToNetIPv6 is a helper function that correctly returns a net.IP with the // correctly padded values. func bigIntToNetIPv6(bi *big.Int) *net.IP { x := make(net.IP, IPv6len) ipv6Bytes := bi.Bytes() // It's possibe for ipv6Bytes to be less than IPv6len bytes in size. If // they are different sizes we to pad the size of response. if len(ipv6Bytes) < IPv6len { buf := new(bytes.Buffer) buf.Grow(IPv6len) for i := len(ipv6Bytes); i < IPv6len; i++ { if err := binary.Write(buf, binary.BigEndian, byte(0)); err != nil { panic(fmt.Sprintf("Unable to pad byte %d of input %v: %v", i, bi, err)) } } for _, b := range ipv6Bytes { if err := binary.Write(buf, binary.BigEndian, b); err != nil { panic(fmt.Sprintf("Unable to preserve endianness of input %v: %v", bi, err)) } } ipv6Bytes = buf.Bytes() } i := copy(x, ipv6Bytes) if i != IPv6len { panic("IPv6 wrong size") } return &x } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/rfc.go ================================================ package sockaddr // ForwardingBlacklist is a faux RFC that includes a list of non-forwardable IP // blocks. const ForwardingBlacklist = 4294967295 const ForwardingBlacklistRFC = "4294967295" // IsRFC tests to see if an SockAddr matches the specified RFC func IsRFC(rfcNum uint, sa SockAddr) bool { rfcNetMap := KnownRFCs() rfcNets, ok := rfcNetMap[rfcNum] if !ok { return false } var contained bool for _, rfcNet := range rfcNets { if rfcNet.Contains(sa) { contained = true break } } return contained } // KnownRFCs returns an initial set of known RFCs. // // NOTE (sean@): As this list evolves over time, please submit patches to keep // this list current. If something isn't right, inquire, as it may just be a // bug on my part. Some of the inclusions were based on my judgement as to what // would be a useful value (e.g. RFC3330). // // Useful resources: // // * https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml // * https://www.iana.org/assignments/ipv6-unicast-address-assignments/ipv6-unicast-address-assignments.xhtml // * https://www.iana.org/assignments/ipv6-address-space/ipv6-address-space.xhtml func KnownRFCs() map[uint]SockAddrs { // NOTE(sean@): Multiple SockAddrs per RFC lend themselves well to a // RADIX tree, but `ENOTIME`. Patches welcome. return map[uint]SockAddrs{ 919: { // [RFC919] Broadcasting Internet Datagrams MustIPv4Addr("255.255.255.255/32"), // [RFC1122], §7 Broadcast IP Addressing - Proposed Standards }, 1122: { // [RFC1122] Requirements for Internet Hosts -- Communication Layers MustIPv4Addr("0.0.0.0/8"), // [RFC1122], §3.2.1.3 MustIPv4Addr("127.0.0.0/8"), // [RFC1122], §3.2.1.3 }, 1112: { // [RFC1112] Host Extensions for IP Multicasting MustIPv4Addr("224.0.0.0/4"), // [RFC1112], §4 Host Group Addresses }, 1918: { // [RFC1918] Address Allocation for Private Internets MustIPv4Addr("10.0.0.0/8"), MustIPv4Addr("172.16.0.0/12"), MustIPv4Addr("192.168.0.0/16"), }, 2544: { // [RFC2544] Benchmarking Methodology for Network // Interconnect Devices MustIPv4Addr("198.18.0.0/15"), }, 2765: { // [RFC2765] Stateless IP/ICMP Translation Algorithm // (SIIT) (obsoleted by RFCs 6145, which itself was // later obsoleted by 7915). // [RFC2765], §2.1 Addresses MustIPv6Addr("0:0:0:0:0:ffff:0:0/96"), }, 2928: { // [RFC2928] Initial IPv6 Sub-TLA ID Assignments MustIPv6Addr("2001::/16"), // Superblock //MustIPv6Addr("2001:0000::/23"), // IANA //MustIPv6Addr("2001:0200::/23"), // APNIC //MustIPv6Addr("2001:0400::/23"), // ARIN //MustIPv6Addr("2001:0600::/23"), // RIPE NCC //MustIPv6Addr("2001:0800::/23"), // (future assignment) // ... //MustIPv6Addr("2001:FE00::/23"), // (future assignment) }, 3056: { // 6to4 address // [RFC3056] Connection of IPv6 Domains via IPv4 Clouds // [RFC3056], §2 IPv6 Prefix Allocation MustIPv6Addr("2002::/16"), }, 3068: { // [RFC3068] An Anycast Prefix for 6to4 Relay Routers // (obsolete by RFC7526) // [RFC3068], § 6to4 Relay anycast address MustIPv4Addr("192.88.99.0/24"), // [RFC3068], §2.5 6to4 IPv6 relay anycast address // // NOTE: /120 == 128-(32-24) MustIPv6Addr("2002:c058:6301::/120"), }, 3171: { // [RFC3171] IANA Guidelines for IPv4 Multicast Address Assignments MustIPv4Addr("224.0.0.0/4"), }, 3330: { // [RFC3330] Special-Use IPv4 Addresses // Addresses in this block refer to source hosts on // "this" network. Address 0.0.0.0/32 may be used as a // source address for this host on this network; other // addresses within 0.0.0.0/8 may be used to refer to // specified hosts on this network [RFC1700, page 4]. MustIPv4Addr("0.0.0.0/8"), // 10.0.0.0/8 - This block is set aside for use in // private networks. Its intended use is documented in // [RFC1918]. Addresses within this block should not // appear on the public Internet. MustIPv4Addr("10.0.0.0/8"), // 14.0.0.0/8 - This block is set aside for assignments // to the international system of Public Data Networks // [RFC1700, page 181]. The registry of assignments // within this block can be accessed from the "Public // Data Network Numbers" link on the web page at // http://www.iana.org/numbers.html. Addresses within // this block are assigned to users and should be // treated as such. // 24.0.0.0/8 - This block was allocated in early 1996 // for use in provisioning IP service over cable // television systems. Although the IANA initially was // involved in making assignments to cable operators, // this responsibility was transferred to American // Registry for Internet Numbers (ARIN) in May 2001. // Addresses within this block are assigned in the // normal manner and should be treated as such. // 39.0.0.0/8 - This block was used in the "Class A // Subnet Experiment" that commenced in May 1995, as // documented in [RFC1797]. The experiment has been // completed and this block has been returned to the // pool of addresses reserved for future allocation or // assignment. This block therefore no longer has a // special use and is subject to allocation to a // Regional Internet Registry for assignment in the // normal manner. // 127.0.0.0/8 - This block is assigned for use as the Internet host // loopback address. A datagram sent by a higher level protocol to an // address anywhere within this block should loop back inside the host. // This is ordinarily implemented using only 127.0.0.1/32 for loopback, // but no addresses within this block should ever appear on any network // anywhere [RFC1700, page 5]. MustIPv4Addr("127.0.0.0/8"), // 128.0.0.0/16 - This block, corresponding to the // numerically lowest of the former Class B addresses, // was initially and is still reserved by the IANA. // Given the present classless nature of the IP address // space, the basis for the reservation no longer // applies and addresses in this block are subject to // future allocation to a Regional Internet Registry for // assignment in the normal manner. // 169.254.0.0/16 - This is the "link local" block. It // is allocated for communication between hosts on a // single link. Hosts obtain these addresses by // auto-configuration, such as when a DHCP server may // not be found. MustIPv4Addr("169.254.0.0/16"), // 172.16.0.0/12 - This block is set aside for use in // private networks. Its intended use is documented in // [RFC1918]. Addresses within this block should not // appear on the public Internet. MustIPv4Addr("172.16.0.0/12"), // 191.255.0.0/16 - This block, corresponding to the numerically highest // to the former Class B addresses, was initially and is still reserved // by the IANA. Given the present classless nature of the IP address // space, the basis for the reservation no longer applies and addresses // in this block are subject to future allocation to a Regional Internet // Registry for assignment in the normal manner. // 192.0.0.0/24 - This block, corresponding to the // numerically lowest of the former Class C addresses, // was initially and is still reserved by the IANA. // Given the present classless nature of the IP address // space, the basis for the reservation no longer // applies and addresses in this block are subject to // future allocation to a Regional Internet Registry for // assignment in the normal manner. // 192.0.2.0/24 - This block is assigned as "TEST-NET" for use in // documentation and example code. It is often used in conjunction with // domain names example.com or example.net in vendor and protocol // documentation. Addresses within this block should not appear on the // public Internet. MustIPv4Addr("192.0.2.0/24"), // 192.88.99.0/24 - This block is allocated for use as 6to4 relay // anycast addresses, according to [RFC3068]. MustIPv4Addr("192.88.99.0/24"), // 192.168.0.0/16 - This block is set aside for use in private networks. // Its intended use is documented in [RFC1918]. Addresses within this // block should not appear on the public Internet. MustIPv4Addr("192.168.0.0/16"), // 198.18.0.0/15 - This block has been allocated for use // in benchmark tests of network interconnect devices. // Its use is documented in [RFC2544]. MustIPv4Addr("198.18.0.0/15"), // 223.255.255.0/24 - This block, corresponding to the // numerically highest of the former Class C addresses, // was initially and is still reserved by the IANA. // Given the present classless nature of the IP address // space, the basis for the reservation no longer // applies and addresses in this block are subject to // future allocation to a Regional Internet Registry for // assignment in the normal manner. // 224.0.0.0/4 - This block, formerly known as the Class // D address space, is allocated for use in IPv4 // multicast address assignments. The IANA guidelines // for assignments from this space are described in // [RFC3171]. MustIPv4Addr("224.0.0.0/4"), // 240.0.0.0/4 - This block, formerly known as the Class E address // space, is reserved. The "limited broadcast" destination address // 255.255.255.255 should never be forwarded outside the (sub-)net of // the source. The remainder of this space is reserved // for future use. [RFC1700, page 4] MustIPv4Addr("240.0.0.0/4"), }, 3849: { // [RFC3849] IPv6 Address Prefix Reserved for Documentation MustIPv6Addr("2001:db8::/32"), // [RFC3849], §4 IANA Considerations }, 3927: { // [RFC3927] Dynamic Configuration of IPv4 Link-Local Addresses MustIPv4Addr("169.254.0.0/16"), // [RFC3927], §2.1 Link-Local Address Selection }, 4038: { // [RFC4038] Application Aspects of IPv6 Transition // [RFC4038], §4.2. IPv6 Applications in a Dual-Stack Node MustIPv6Addr("0:0:0:0:0:ffff::/96"), }, 4193: { // [RFC4193] Unique Local IPv6 Unicast Addresses MustIPv6Addr("fc00::/7"), }, 4291: { // [RFC4291] IP Version 6 Addressing Architecture // [RFC4291], §2.5.2 The Unspecified Address MustIPv6Addr("::/128"), // [RFC4291], §2.5.3 The Loopback Address MustIPv6Addr("::1/128"), // [RFC4291], §2.5.5.1. IPv4-Compatible IPv6 Address MustIPv6Addr("::/96"), // [RFC4291], §2.5.5.2. IPv4-Mapped IPv6 Address MustIPv6Addr("::ffff:0:0/96"), // [RFC4291], §2.5.6 Link-Local IPv6 Unicast Addresses MustIPv6Addr("fe80::/10"), // [RFC4291], §2.5.7 Site-Local IPv6 Unicast Addresses // (depreciated) MustIPv6Addr("fec0::/10"), // [RFC4291], §2.7 Multicast Addresses MustIPv6Addr("ff00::/8"), // IPv6 Multicast Information. // // In the following "table" below, `ff0x` is replaced // with the following values depending on the scope of // the query: // // IPv6 Multicast Scopes: // * ff00/9 // reserved // * ff01/9 // interface-local // * ff02/9 // link-local // * ff03/9 // realm-local // * ff04/9 // admin-local // * ff05/9 // site-local // * ff08/9 // organization-local // * ff0e/9 // global // * ff0f/9 // reserved // // IPv6 Multicast Addresses: // * ff0x::2 // All routers // * ff02::5 // OSPFIGP // * ff02::6 // OSPFIGP Designated Routers // * ff02::9 // RIP Routers // * ff02::a // EIGRP Routers // * ff02::d // All PIM Routers // * ff02::1a // All RPL Routers // * ff0x::fb // mDNSv6 // * ff0x::101 // All Network Time Protocol (NTP) servers // * ff02::1:1 // Link Name // * ff02::1:2 // All-dhcp-agents // * ff02::1:3 // Link-local Multicast Name Resolution // * ff05::1:3 // All-dhcp-servers // * ff02::1:ff00:0/104 // Solicited-node multicast address. // * ff02::2:ff00:0/104 // Node Information Queries }, 4380: { // [RFC4380] Teredo: Tunneling IPv6 over UDP through // Network Address Translations (NATs) // [RFC4380], §2.6 Global Teredo IPv6 Service Prefix MustIPv6Addr("2001:0000::/32"), }, 4773: { // [RFC4773] Administration of the IANA Special Purpose IPv6 Address Block MustIPv6Addr("2001:0000::/23"), // IANA }, 4843: { // [RFC4843] An IPv6 Prefix for Overlay Routable Cryptographic Hash Identifiers (ORCHID) MustIPv6Addr("2001:10::/28"), // [RFC4843], §7 IANA Considerations }, 5180: { // [RFC5180] IPv6 Benchmarking Methodology for Network Interconnect Devices MustIPv6Addr("2001:0200::/48"), // [RFC5180], §8 IANA Considerations }, 5735: { // [RFC5735] Special Use IPv4 Addresses MustIPv4Addr("192.0.2.0/24"), // TEST-NET-1 MustIPv4Addr("198.51.100.0/24"), // TEST-NET-2 MustIPv4Addr("203.0.113.0/24"), // TEST-NET-3 MustIPv4Addr("198.18.0.0/15"), // Benchmarks }, 5737: { // [RFC5737] IPv4 Address Blocks Reserved for Documentation MustIPv4Addr("192.0.2.0/24"), // TEST-NET-1 MustIPv4Addr("198.51.100.0/24"), // TEST-NET-2 MustIPv4Addr("203.0.113.0/24"), // TEST-NET-3 }, 6052: { // [RFC6052] IPv6 Addressing of IPv4/IPv6 Translators MustIPv6Addr("64:ff9b::/96"), // [RFC6052], §2.1. Well-Known Prefix }, 6333: { // [RFC6333] Dual-Stack Lite Broadband Deployments Following IPv4 Exhaustion MustIPv4Addr("192.0.0.0/29"), // [RFC6333], §5.7 Well-Known IPv4 Address }, 6598: { // [RFC6598] IANA-Reserved IPv4 Prefix for Shared Address Space MustIPv4Addr("100.64.0.0/10"), }, 6666: { // [RFC6666] A Discard Prefix for IPv6 MustIPv6Addr("0100::/64"), }, 6890: { // [RFC6890] Special-Purpose IP Address Registries // From "RFC6890 §2.2.1 Information Requirements": /* The IPv4 and IPv6 Special-Purpose Address Registries maintain the following information regarding each entry: o Address Block - A block of IPv4 or IPv6 addresses that has been registered for a special purpose. o Name - A descriptive name for the special-purpose address block. o RFC - The RFC through which the special-purpose address block was requested. o Allocation Date - The date upon which the special-purpose address block was allocated. o Termination Date - The date upon which the allocation is to be terminated. This field is applicable for limited-use allocations only. o Source - A boolean value indicating whether an address from the allocated special-purpose address block is valid when used as the source address of an IP datagram that transits two devices. o Destination - A boolean value indicating whether an address from the allocated special-purpose address block is valid when used as the destination address of an IP datagram that transits two devices. o Forwardable - A boolean value indicating whether a router may forward an IP datagram whose destination address is drawn from the allocated special-purpose address block between external interfaces. o Global - A boolean value indicating whether an IP datagram whose destination address is drawn from the allocated special-purpose address block is forwardable beyond a specified administrative domain. o Reserved-by-Protocol - A boolean value indicating whether the special-purpose address block is reserved by IP, itself. This value is "TRUE" if the RFC that created the special-purpose address block requires all compliant IP implementations to behave in a special way when processing packets either to or from addresses contained by the address block. If the value of "Destination" is FALSE, the values of "Forwardable" and "Global" must also be false. */ /*+----------------------+----------------------------+ * | Attribute | Value | * +----------------------+----------------------------+ * | Address Block | 0.0.0.0/8 | * | Name | "This host on this network"| * | RFC | [RFC1122], Section 3.2.1.3 | * | Allocation Date | September 1981 | * | Termination Date | N/A | * | Source | True | * | Destination | False | * | Forwardable | False | * | Global | False | * | Reserved-by-Protocol | True | * +----------------------+----------------------------+*/ MustIPv4Addr("0.0.0.0/8"), /*+----------------------+---------------+ * | Attribute | Value | * +----------------------+---------------+ * | Address Block | 10.0.0.0/8 | * | Name | Private-Use | * | RFC | [RFC1918] | * | Allocation Date | February 1996 | * | Termination Date | N/A | * | Source | True | * | Destination | True | * | Forwardable | True | * | Global | False | * | Reserved-by-Protocol | False | * +----------------------+---------------+ */ MustIPv4Addr("10.0.0.0/8"), /*+----------------------+----------------------+ | Attribute | Value | +----------------------+----------------------+ | Address Block | 100.64.0.0/10 | | Name | Shared Address Space | | RFC | [RFC6598] | | Allocation Date | April 2012 | | Termination Date | N/A | | Source | True | | Destination | True | | Forwardable | True | | Global | False | | Reserved-by-Protocol | False | +----------------------+----------------------+*/ MustIPv4Addr("100.64.0.0/10"), /*+----------------------+----------------------------+ | Attribute | Value | +----------------------+----------------------------+ | Address Block | 127.0.0.0/8 | | Name | Loopback | | RFC | [RFC1122], Section 3.2.1.3 | | Allocation Date | September 1981 | | Termination Date | N/A | | Source | False [1] | | Destination | False [1] | | Forwardable | False [1] | | Global | False [1] | | Reserved-by-Protocol | True | +----------------------+----------------------------+*/ // [1] Several protocols have been granted exceptions to // this rule. For examples, see [RFC4379] and // [RFC5884]. MustIPv4Addr("127.0.0.0/8"), /*+----------------------+----------------+ | Attribute | Value | +----------------------+----------------+ | Address Block | 169.254.0.0/16 | | Name | Link Local | | RFC | [RFC3927] | | Allocation Date | May 2005 | | Termination Date | N/A | | Source | True | | Destination | True | | Forwardable | False | | Global | False | | Reserved-by-Protocol | True | +----------------------+----------------+*/ MustIPv4Addr("169.254.0.0/16"), /*+----------------------+---------------+ | Attribute | Value | +----------------------+---------------+ | Address Block | 172.16.0.0/12 | | Name | Private-Use | | RFC | [RFC1918] | | Allocation Date | February 1996 | | Termination Date | N/A | | Source | True | | Destination | True | | Forwardable | True | | Global | False | | Reserved-by-Protocol | False | +----------------------+---------------+*/ MustIPv4Addr("172.16.0.0/12"), /*+----------------------+---------------------------------+ | Attribute | Value | +----------------------+---------------------------------+ | Address Block | 192.0.0.0/24 [2] | | Name | IETF Protocol Assignments | | RFC | Section 2.1 of this document | | Allocation Date | January 2010 | | Termination Date | N/A | | Source | False | | Destination | False | | Forwardable | False | | Global | False | | Reserved-by-Protocol | False | +----------------------+---------------------------------+*/ // [2] Not usable unless by virtue of a more specific // reservation. MustIPv4Addr("192.0.0.0/24"), /*+----------------------+--------------------------------+ | Attribute | Value | +----------------------+--------------------------------+ | Address Block | 192.0.0.0/29 | | Name | IPv4 Service Continuity Prefix | | RFC | [RFC6333], [RFC7335] | | Allocation Date | June 2011 | | Termination Date | N/A | | Source | True | | Destination | True | | Forwardable | True | | Global | False | | Reserved-by-Protocol | False | +----------------------+--------------------------------+*/ MustIPv4Addr("192.0.0.0/29"), /*+----------------------+----------------------------+ | Attribute | Value | +----------------------+----------------------------+ | Address Block | 192.0.2.0/24 | | Name | Documentation (TEST-NET-1) | | RFC | [RFC5737] | | Allocation Date | January 2010 | | Termination Date | N/A | | Source | False | | Destination | False | | Forwardable | False | | Global | False | | Reserved-by-Protocol | False | +----------------------+----------------------------+*/ MustIPv4Addr("192.0.2.0/24"), /*+----------------------+--------------------+ | Attribute | Value | +----------------------+--------------------+ | Address Block | 192.88.99.0/24 | | Name | 6to4 Relay Anycast | | RFC | [RFC3068] | | Allocation Date | June 2001 | | Termination Date | N/A | | Source | True | | Destination | True | | Forwardable | True | | Global | True | | Reserved-by-Protocol | False | +----------------------+--------------------+*/ MustIPv4Addr("192.88.99.0/24"), /*+----------------------+----------------+ | Attribute | Value | +----------------------+----------------+ | Address Block | 192.168.0.0/16 | | Name | Private-Use | | RFC | [RFC1918] | | Allocation Date | February 1996 | | Termination Date | N/A | | Source | True | | Destination | True | | Forwardable | True | | Global | False | | Reserved-by-Protocol | False | +----------------------+----------------+*/ MustIPv4Addr("192.168.0.0/16"), /*+----------------------+---------------+ | Attribute | Value | +----------------------+---------------+ | Address Block | 198.18.0.0/15 | | Name | Benchmarking | | RFC | [RFC2544] | | Allocation Date | March 1999 | | Termination Date | N/A | | Source | True | | Destination | True | | Forwardable | True | | Global | False | | Reserved-by-Protocol | False | +----------------------+---------------+*/ MustIPv4Addr("198.18.0.0/15"), /*+----------------------+----------------------------+ | Attribute | Value | +----------------------+----------------------------+ | Address Block | 198.51.100.0/24 | | Name | Documentation (TEST-NET-2) | | RFC | [RFC5737] | | Allocation Date | January 2010 | | Termination Date | N/A | | Source | False | | Destination | False | | Forwardable | False | | Global | False | | Reserved-by-Protocol | False | +----------------------+----------------------------+*/ MustIPv4Addr("198.51.100.0/24"), /*+----------------------+----------------------------+ | Attribute | Value | +----------------------+----------------------------+ | Address Block | 203.0.113.0/24 | | Name | Documentation (TEST-NET-3) | | RFC | [RFC5737] | | Allocation Date | January 2010 | | Termination Date | N/A | | Source | False | | Destination | False | | Forwardable | False | | Global | False | | Reserved-by-Protocol | False | +----------------------+----------------------------+*/ MustIPv4Addr("203.0.113.0/24"), /*+----------------------+----------------------+ | Attribute | Value | +----------------------+----------------------+ | Address Block | 240.0.0.0/4 | | Name | Reserved | | RFC | [RFC1112], Section 4 | | Allocation Date | August 1989 | | Termination Date | N/A | | Source | False | | Destination | False | | Forwardable | False | | Global | False | | Reserved-by-Protocol | True | +----------------------+----------------------+*/ MustIPv4Addr("240.0.0.0/4"), /*+----------------------+----------------------+ | Attribute | Value | +----------------------+----------------------+ | Address Block | 255.255.255.255/32 | | Name | Limited Broadcast | | RFC | [RFC0919], Section 7 | | Allocation Date | October 1984 | | Termination Date | N/A | | Source | False | | Destination | True | | Forwardable | False | | Global | False | | Reserved-by-Protocol | False | +----------------------+----------------------+*/ MustIPv4Addr("255.255.255.255/32"), /*+----------------------+------------------+ | Attribute | Value | +----------------------+------------------+ | Address Block | ::1/128 | | Name | Loopback Address | | RFC | [RFC4291] | | Allocation Date | February 2006 | | Termination Date | N/A | | Source | False | | Destination | False | | Forwardable | False | | Global | False | | Reserved-by-Protocol | True | +----------------------+------------------+*/ MustIPv6Addr("::1/128"), /*+----------------------+---------------------+ | Attribute | Value | +----------------------+---------------------+ | Address Block | ::/128 | | Name | Unspecified Address | | RFC | [RFC4291] | | Allocation Date | February 2006 | | Termination Date | N/A | | Source | True | | Destination | False | | Forwardable | False | | Global | False | | Reserved-by-Protocol | True | +----------------------+---------------------+*/ MustIPv6Addr("::/128"), /*+----------------------+---------------------+ | Attribute | Value | +----------------------+---------------------+ | Address Block | 64:ff9b::/96 | | Name | IPv4-IPv6 Translat. | | RFC | [RFC6052] | | Allocation Date | October 2010 | | Termination Date | N/A | | Source | True | | Destination | True | | Forwardable | True | | Global | True | | Reserved-by-Protocol | False | +----------------------+---------------------+*/ MustIPv6Addr("64:ff9b::/96"), /*+----------------------+---------------------+ | Attribute | Value | +----------------------+---------------------+ | Address Block | ::ffff:0:0/96 | | Name | IPv4-mapped Address | | RFC | [RFC4291] | | Allocation Date | February 2006 | | Termination Date | N/A | | Source | False | | Destination | False | | Forwardable | False | | Global | False | | Reserved-by-Protocol | True | +----------------------+---------------------+*/ MustIPv6Addr("::ffff:0:0/96"), /*+----------------------+----------------------------+ | Attribute | Value | +----------------------+----------------------------+ | Address Block | 100::/64 | | Name | Discard-Only Address Block | | RFC | [RFC6666] | | Allocation Date | June 2012 | | Termination Date | N/A | | Source | True | | Destination | True | | Forwardable | True | | Global | False | | Reserved-by-Protocol | False | +----------------------+----------------------------+*/ MustIPv6Addr("100::/64"), /*+----------------------+---------------------------+ | Attribute | Value | +----------------------+---------------------------+ | Address Block | 2001::/23 | | Name | IETF Protocol Assignments | | RFC | [RFC2928] | | Allocation Date | September 2000 | | Termination Date | N/A | | Source | False[1] | | Destination | False[1] | | Forwardable | False[1] | | Global | False[1] | | Reserved-by-Protocol | False | +----------------------+---------------------------+*/ // [1] Unless allowed by a more specific allocation. MustIPv6Addr("2001::/16"), /*+----------------------+----------------+ | Attribute | Value | +----------------------+----------------+ | Address Block | 2001::/32 | | Name | TEREDO | | RFC | [RFC4380] | | Allocation Date | January 2006 | | Termination Date | N/A | | Source | True | | Destination | True | | Forwardable | True | | Global | False | | Reserved-by-Protocol | False | +----------------------+----------------+*/ // Covered by previous entry, included for completeness. // // MustIPv6Addr("2001::/16"), /*+----------------------+----------------+ | Attribute | Value | +----------------------+----------------+ | Address Block | 2001:2::/48 | | Name | Benchmarking | | RFC | [RFC5180] | | Allocation Date | April 2008 | | Termination Date | N/A | | Source | True | | Destination | True | | Forwardable | True | | Global | False | | Reserved-by-Protocol | False | +----------------------+----------------+*/ // Covered by previous entry, included for completeness. // // MustIPv6Addr("2001:2::/48"), /*+----------------------+---------------+ | Attribute | Value | +----------------------+---------------+ | Address Block | 2001:db8::/32 | | Name | Documentation | | RFC | [RFC3849] | | Allocation Date | July 2004 | | Termination Date | N/A | | Source | False | | Destination | False | | Forwardable | False | | Global | False | | Reserved-by-Protocol | False | +----------------------+---------------+*/ // Covered by previous entry, included for completeness. // // MustIPv6Addr("2001:db8::/32"), /*+----------------------+--------------+ | Attribute | Value | +----------------------+--------------+ | Address Block | 2001:10::/28 | | Name | ORCHID | | RFC | [RFC4843] | | Allocation Date | March 2007 | | Termination Date | March 2014 | | Source | False | | Destination | False | | Forwardable | False | | Global | False | | Reserved-by-Protocol | False | +----------------------+--------------+*/ // Covered by previous entry, included for completeness. // // MustIPv6Addr("2001:10::/28"), /*+----------------------+---------------+ | Attribute | Value | +----------------------+---------------+ | Address Block | 2002::/16 [2] | | Name | 6to4 | | RFC | [RFC3056] | | Allocation Date | February 2001 | | Termination Date | N/A | | Source | True | | Destination | True | | Forwardable | True | | Global | N/A [2] | | Reserved-by-Protocol | False | +----------------------+---------------+*/ // [2] See [RFC3056] for details. MustIPv6Addr("2002::/16"), /*+----------------------+--------------+ | Attribute | Value | +----------------------+--------------+ | Address Block | fc00::/7 | | Name | Unique-Local | | RFC | [RFC4193] | | Allocation Date | October 2005 | | Termination Date | N/A | | Source | True | | Destination | True | | Forwardable | True | | Global | False | | Reserved-by-Protocol | False | +----------------------+--------------+*/ MustIPv6Addr("fc00::/7"), /*+----------------------+-----------------------+ | Attribute | Value | +----------------------+-----------------------+ | Address Block | fe80::/10 | | Name | Linked-Scoped Unicast | | RFC | [RFC4291] | | Allocation Date | February 2006 | | Termination Date | N/A | | Source | True | | Destination | True | | Forwardable | False | | Global | False | | Reserved-by-Protocol | True | +----------------------+-----------------------+*/ MustIPv6Addr("fe80::/10"), }, 7335: { // [RFC7335] IPv4 Service Continuity Prefix MustIPv4Addr("192.0.0.0/29"), // [RFC7335], §6 IANA Considerations }, ForwardingBlacklist: { // Pseudo-RFC // Blacklist of non-forwardable IP blocks taken from RFC6890 // // TODO: the attributes for forwardable should be // searcahble and embedded in the main list of RFCs // above. MustIPv4Addr("0.0.0.0/8"), MustIPv4Addr("127.0.0.0/8"), MustIPv4Addr("169.254.0.0/16"), MustIPv4Addr("192.0.0.0/24"), MustIPv4Addr("192.0.2.0/24"), MustIPv4Addr("198.51.100.0/24"), MustIPv4Addr("203.0.113.0/24"), MustIPv4Addr("240.0.0.0/4"), MustIPv4Addr("255.255.255.255/32"), MustIPv6Addr("::1/128"), MustIPv6Addr("::/128"), MustIPv6Addr("::ffff:0:0/96"), // There is no way of expressing a whitelist per RFC2928 // atm without creating a negative mask, which I don't // want to do atm. //MustIPv6Addr("2001::/23"), MustIPv6Addr("2001:db8::/32"), MustIPv6Addr("2001:10::/28"), MustIPv6Addr("fe80::/10"), }, } } // VisitAllRFCs iterates over all known RFCs and calls the visitor func VisitAllRFCs(fn func(rfcNum uint, sockaddrs SockAddrs)) { rfcNetMap := KnownRFCs() // Blacklist of faux-RFCs. Don't show the world that we're abusing the // RFC system in this library. rfcBlacklist := map[uint]struct{}{ ForwardingBlacklist: {}, } for rfcNum, sas := range rfcNetMap { if _, found := rfcBlacklist[rfcNum]; !found { fn(rfcNum, sas) } } } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/route_info.go ================================================ package sockaddr import "errors" var ( ErrNoInterface = errors.New("No default interface found (unsupported platform)") ErrNoRoute = errors.New("no route info found (unsupported platform)") ) // RouteInterface specifies an interface for obtaining memoized route table and // network information from a given OS. type RouteInterface interface { // GetDefaultInterfaceName returns the name of the interface that has a // default route or an error and an empty string if a problem was // encountered. GetDefaultInterfaceName() (string, error) } type routeInfo struct { cmds map[string][]string } // VisitCommands visits each command used by the platform-specific RouteInfo // implementation. func (ri routeInfo) VisitCommands(fn func(name string, cmd []string)) { for k, v := range ri.cmds { cmds := append([]string(nil), v...) fn(k, cmds) } } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/route_info_aix.go ================================================ //go:build aix package sockaddr import ( "errors" "os/exec" ) var cmds map[string][]string = map[string][]string{ "route": {"/usr/sbin/route", "-n", "get", "default"}, } // NewRouteInfo returns a BSD-specific implementation of the RouteInfo // interface. func NewRouteInfo() (routeInfo, error) { return routeInfo{ cmds: cmds, }, nil } // GetDefaultInterfaceName returns the interface name attached to the default // route on the default interface. func (ri routeInfo) GetDefaultInterfaceName() (string, error) { out, err := exec.Command(cmds["route"][0], cmds["route"][1:]...).Output() if err != nil { return "", err } var ifName string if ifName, err = parseDefaultIfNameFromRoute(string(out)); err != nil { return "", errors.New("No default interface found") } return ifName, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/route_info_android.go ================================================ //go:build android package sockaddr import ( "errors" "os/exec" ) // NewRouteInfo returns a Android-specific implementation of the RouteInfo // interface. func NewRouteInfo() (routeInfo, error) { return routeInfo{ cmds: map[string][]string{"ip": {"/system/bin/ip", "route", "get", "8.8.8.8"}}, }, nil } // GetDefaultInterfaceName returns the interface name attached to the default // route on the default interface. func (ri routeInfo) GetDefaultInterfaceName() (string, error) { out, err := exec.Command(ri.cmds["ip"][0], ri.cmds["ip"][1:]...).Output() if err != nil { return "", err } var ifName string if ifName, err = parseDefaultIfNameFromIPCmdAndroid(string(out)); err != nil { return "", errors.New("No default interface found") } return ifName, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/route_info_bsd.go ================================================ //go:build darwin || dragonfly || freebsd || netbsd || openbsd // +build darwin dragonfly freebsd netbsd openbsd package sockaddr import "os/exec" var cmds = map[string][]string{ "route": {"/sbin/route", "-n", "get", "default"}, } // NewRouteInfo returns a BSD-specific implementation of the RouteInfo // interface. func NewRouteInfo() (routeInfo, error) { return routeInfo{ cmds: cmds, }, nil } // GetDefaultInterfaceName returns the interface name attached to the default // route on the default interface. func (ri routeInfo) GetDefaultInterfaceName() (string, error) { out, err := exec.Command(cmds["route"][0], cmds["route"][1:]...).Output() if err != nil { return "", err } var ifName string if ifName, err = parseDefaultIfNameFromRoute(string(out)); err != nil { return "", err } return ifName, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/route_info_default.go ================================================ //go:build nacl || plan9 || js // +build nacl plan9 js package sockaddr // getDefaultIfName is the default interface function for unsupported platforms. func getDefaultIfName() (string, error) { return "", ErrNoInterface } func NewRouteInfo() (routeInfo, error) { return routeInfo{}, ErrNoRoute } // GetDefaultInterfaceName returns the interface name attached to the default // route on the default interface. func (ri routeInfo) GetDefaultInterfaceName() (string, error) { return "", ErrNoInterface } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/route_info_linux.go ================================================ //go:build !android // +build !android package sockaddr import ( "errors" "os/exec" ) // NewRouteInfo returns a Linux-specific implementation of the RouteInfo // interface. func NewRouteInfo() (routeInfo, error) { // CoreOS Container Linux moved ip to /usr/bin/ip, so look it up on // $PATH and fallback to /sbin/ip on error. path, _ := exec.LookPath("ip") if path == "" { path = "/sbin/ip" } return routeInfo{ cmds: map[string][]string{"ip": {path, "route"}}, }, nil } // GetDefaultInterfaceName returns the interface name attached to the default // route on the default interface. func (ri routeInfo) GetDefaultInterfaceName() (string, error) { out, err := exec.Command(ri.cmds["ip"][0], ri.cmds["ip"][1:]...).Output() if err != nil { return "", err } var ifName string if ifName, err = parseDefaultIfNameFromIPCmd(string(out)); err != nil { return "", errors.New("No default interface found") } return ifName, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/route_info_solaris.go ================================================ //go:build solaris package sockaddr import ( "errors" "os/exec" ) var cmds map[string][]string = map[string][]string{ "route": {"/usr/sbin/route", "-n", "get", "default"}, } // NewRouteInfo returns a BSD-specific implementation of the RouteInfo // interface. func NewRouteInfo() (routeInfo, error) { return routeInfo{ cmds: cmds, }, nil } // GetDefaultInterfaceName returns the interface name attached to the default // route on the default interface. func (ri routeInfo) GetDefaultInterfaceName() (string, error) { out, err := exec.Command(cmds["route"][0], cmds["route"][1:]...).Output() if err != nil { return "", err } var ifName string if ifName, err = parseDefaultIfNameFromRoute(string(out)); err != nil { return "", errors.New("No default interface found") } return ifName, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/route_info_test_windows.go ================================================ package sockaddr import "testing" func Test_parseWindowsDefaultIfName_new_vs_old(t *testing.T) { if !hasPowershell() { t.Skip("this test requires powershell.") return } ri, err := NewRouteInfo() if err != nil { t.Fatalf("bad: %v", err) } psVer, err1 := ri.GetDefaultInterfaceName() legacyVer, err2 := ri.GetDefaultInterfaceNameLegacy() if err1 != nil { t.Errorf("err != nil for GetDefaultInterfaceName - %v", err1) } if err2 != nil { t.Errorf("err != nil for GetDefaultInterfaceNameLegacy - %v", err2) } if psVer != legacyVer { t.Errorf("got %s; want %s", psVer, legacyVer) } } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/route_info_windows.go ================================================ package sockaddr import ( "os/exec" "strings" ) var cmds map[string][]string = map[string][]string{ "defaultInterface": {"powershell", "Get-NetRoute -DestinationPrefix '0.0.0.0/0' | select -ExpandProperty InterfaceAlias"}, // These commands enable GetDefaultInterfaceNameLegacy and should be removed // when it is. "netstat": {"netstat", "-rn"}, "ipconfig": {"ipconfig"}, } // NewRouteInfo returns a BSD-specific implementation of the RouteInfo // interface. func NewRouteInfo() (routeInfo, error) { return routeInfo{ cmds: cmds, }, nil } // GetDefaultInterfaceName returns the interface name attached to the default // route on the default interface. func (ri routeInfo) GetDefaultInterfaceName() (string, error) { if !hasPowershell() { // No powershell, fallback to legacy method return ri.GetDefaultInterfaceNameLegacy() } ifNameOut, err := exec.Command(cmds["defaultInterface"][0], cmds["defaultInterface"][1:]...).Output() if err != nil { return "", err } ifName := strings.TrimSpace(string(ifNameOut[:])) return ifName, nil } // GetDefaultInterfaceNameLegacy provides legacy behavior for GetDefaultInterfaceName // on Windows machines without powershell. func (ri routeInfo) GetDefaultInterfaceNameLegacy() (string, error) { ifNameOut, err := exec.Command(cmds["netstat"][0], cmds["netstat"][1:]...).Output() if err != nil { return "", err } ipconfigOut, err := exec.Command(cmds["ipconfig"][0], cmds["ipconfig"][1:]...).Output() if err != nil { return "", err } ifName, err := parseDefaultIfNameWindows(string(ifNameOut), string(ipconfigOut)) if err != nil { return "", err } return ifName, nil } func hasPowershell() bool { _, err := exec.LookPath("powershell") return (err != nil) } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/sockaddr.go ================================================ package sockaddr import ( "encoding/json" "fmt" "strings" ) type SockAddrType int type AttrName string const ( TypeUnknown SockAddrType = 0x0 TypeUnix = 0x1 TypeIPv4 = 0x2 TypeIPv6 = 0x4 // TypeIP is the union of TypeIPv4 and TypeIPv6 TypeIP = 0x6 ) type SockAddr interface { // CmpRFC returns 0 if SockAddr exactly matches one of the matched RFC // networks, -1 if the receiver is contained within the RFC network, or // 1 if the address is not contained within the RFC. CmpRFC(rfcNum uint, sa SockAddr) int // Contains returns true if the SockAddr arg is contained within the // receiver Contains(SockAddr) bool // Equal allows for the comparison of two SockAddrs Equal(SockAddr) bool DialPacketArgs() (string, string) DialStreamArgs() (string, string) ListenPacketArgs() (string, string) ListenStreamArgs() (string, string) // String returns the string representation of SockAddr String() string // Type returns the SockAddrType Type() SockAddrType } // sockAddrAttrMap is a map of the SockAddr type-specific attributes. var sockAddrAttrMap map[AttrName]func(SockAddr) string var sockAddrAttrs []AttrName func init() { sockAddrInit() } // New creates a new SockAddr from the string. The order in which New() // attempts to construct a SockAddr is: IPv4Addr, IPv6Addr, SockAddrUnix. // // NOTE: New() relies on the heuristic wherein if the path begins with either a // '.' or '/' character before creating a new UnixSock. For UNIX sockets that // are absolute paths or are nested within a sub-directory, this works as // expected, however if the UNIX socket is contained in the current working // directory, this will fail unless the path begins with "./" // (e.g. "./my-local-socket"). Calls directly to NewUnixSock() do not suffer // this limitation. Invalid IP addresses such as "256.0.0.0/-1" will run afoul // of this heuristic and be assumed to be a valid UNIX socket path (which they // are, but it is probably not what you want and you won't realize it until you // stat(2) the file system to discover it doesn't exist). func NewSockAddr(s string) (SockAddr, error) { ipv4Addr, err := NewIPv4Addr(s) if err == nil { return ipv4Addr, nil } ipv6Addr, err := NewIPv6Addr(s) if err == nil { return ipv6Addr, nil } // Check to make sure the string begins with either a '.' or '/', or // contains a '/'. if len(s) > 1 && (strings.IndexAny(s[0:1], "./") != -1 || strings.IndexByte(s, '/') != -1) { unixSock, err := NewUnixSock(s) if err == nil { return unixSock, nil } } return nil, fmt.Errorf("Unable to convert %q to an IPv4 or IPv6 address, or a UNIX Socket", s) } // ToIPAddr returns an IPAddr type or nil if the type conversion fails. func ToIPAddr(sa SockAddr) *IPAddr { ipa, ok := sa.(IPAddr) if !ok { return nil } return &ipa } // ToIPv4Addr returns an IPv4Addr type or nil if the type conversion fails. func ToIPv4Addr(sa SockAddr) *IPv4Addr { switch v := sa.(type) { case IPv4Addr: return &v default: return nil } } // ToIPv6Addr returns an IPv6Addr type or nil if the type conversion fails. func ToIPv6Addr(sa SockAddr) *IPv6Addr { switch v := sa.(type) { case IPv6Addr: return &v default: return nil } } // ToUnixSock returns a UnixSock type or nil if the type conversion fails. func ToUnixSock(sa SockAddr) *UnixSock { switch v := sa.(type) { case UnixSock: return &v default: return nil } } // SockAddrAttr returns a string representation of an attribute for the given // SockAddr. func SockAddrAttr(sa SockAddr, selector AttrName) string { fn, found := sockAddrAttrMap[selector] if !found { return "" } return fn(sa) } // String() for SockAddrType returns a string representation of the // SockAddrType (e.g. "IPv4", "IPv6", "UNIX", "IP", or "unknown"). func (sat SockAddrType) String() string { switch sat { case TypeIPv4: return "IPv4" case TypeIPv6: return "IPv6" // There is no concrete "IP" type. Leaving here as a reminder. // case TypeIP: // return "IP" case TypeUnix: return "UNIX" default: panic("unsupported type") } } // sockAddrInit is called once at init() func sockAddrInit() { sockAddrAttrs = []AttrName{ "type", // type should be first "string", } sockAddrAttrMap = map[AttrName]func(sa SockAddr) string{ "string": func(sa SockAddr) string { return sa.String() }, "type": func(sa SockAddr) string { return sa.Type().String() }, } } // UnixSockAttrs returns a list of attributes supported by the UnixSock type func SockAddrAttrs() []AttrName { return sockAddrAttrs } // Although this is pretty trivial to do in a program, having the logic here is // useful all around. Note that this marshals into a *string* -- the underlying // string representation of the sockaddr. If you then unmarshal into this type // in Go, all will work as expected, but externally you can take what comes out // and use the string value directly. type SockAddrMarshaler struct { SockAddr } func (s *SockAddrMarshaler) MarshalJSON() ([]byte, error) { return json.Marshal(s.SockAddr.String()) } func (s *SockAddrMarshaler) UnmarshalJSON(in []byte) error { var str string err := json.Unmarshal(in, &str) if err != nil { return err } sa, err := NewSockAddr(str) if err != nil { return err } s.SockAddr = sa return nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/sockaddrs.go ================================================ package sockaddr import ( "bytes" "sort" ) // SockAddrs is a slice of SockAddrs type SockAddrs []SockAddr func (s SockAddrs) Len() int { return len(s) } func (s SockAddrs) Swap(i, j int) { s[i], s[j] = s[j], s[i] } // CmpAddrFunc is the function signature that must be met to be used in the // OrderedAddrBy multiAddrSorter type CmpAddrFunc func(p1, p2 *SockAddr) int // multiAddrSorter implements the Sort interface, sorting the SockAddrs within. type multiAddrSorter struct { addrs SockAddrs cmp []CmpAddrFunc } // Sort sorts the argument slice according to the Cmp functions passed to // OrderedAddrBy. func (ms *multiAddrSorter) Sort(sockAddrs SockAddrs) { ms.addrs = sockAddrs sort.Sort(ms) } // OrderedAddrBy sorts SockAddr by the list of sort function pointers. func OrderedAddrBy(cmpFuncs ...CmpAddrFunc) *multiAddrSorter { return &multiAddrSorter{ cmp: cmpFuncs, } } // Len is part of sort.Interface. func (ms *multiAddrSorter) Len() int { return len(ms.addrs) } // Less is part of sort.Interface. It is implemented by looping along the // Cmp() functions until it finds a comparison that is either less than, // equal to, or greater than. func (ms *multiAddrSorter) Less(i, j int) bool { p, q := &ms.addrs[i], &ms.addrs[j] // Try all but the last comparison. var k int for k = 0; k < len(ms.cmp)-1; k++ { cmp := ms.cmp[k] x := cmp(p, q) switch x { case -1: // p < q, so we have a decision. return true case 1: // p > q, so we have a decision. return false } // p == q; try the next comparison. } // All comparisons to here said "equal", so just return whatever the // final comparison reports. switch ms.cmp[k](p, q) { case -1: return true case 1: return false default: // Still a tie! Now what? return false } } // Swap is part of sort.Interface. func (ms *multiAddrSorter) Swap(i, j int) { ms.addrs[i], ms.addrs[j] = ms.addrs[j], ms.addrs[i] } const ( // NOTE (sean@): These constants are here for code readability only and // are sprucing up the code for readability purposes. Some of the // Cmp*() variants have confusing logic (especially when dealing with // mixed-type comparisons) and this, I think, has made it easier to grok // the code faster. sortReceiverBeforeArg = -1 sortDeferDecision = 0 sortArgBeforeReceiver = 1 ) // AscAddress is a sorting function to sort SockAddrs by their respective // address type. Non-equal types are deferred in the sort. func AscAddress(p1Ptr, p2Ptr *SockAddr) int { p1 := *p1Ptr p2 := *p2Ptr switch v := p1.(type) { case IPv4Addr: return v.CmpAddress(p2) case IPv6Addr: return v.CmpAddress(p2) case UnixSock: return v.CmpAddress(p2) default: return sortDeferDecision } } // AscPort is a sorting function to sort SockAddrs by their respective address // type. Non-equal types are deferred in the sort. func AscPort(p1Ptr, p2Ptr *SockAddr) int { p1 := *p1Ptr p2 := *p2Ptr switch v := p1.(type) { case IPv4Addr: return v.CmpPort(p2) case IPv6Addr: return v.CmpPort(p2) default: return sortDeferDecision } } // AscPrivate is a sorting function to sort "more secure" private values before // "more public" values. Both IPv4 and IPv6 are compared against RFC6890 // (RFC6890 includes, and is not limited to, RFC1918 and RFC6598 for IPv4, and // IPv6 includes RFC4193). func AscPrivate(p1Ptr, p2Ptr *SockAddr) int { p1 := *p1Ptr p2 := *p2Ptr switch v := p1.(type) { case IPv4Addr, IPv6Addr: return v.CmpRFC(6890, p2) default: return sortDeferDecision } } // AscNetworkSize is a sorting function to sort SockAddrs based on their network // size. Non-equal types are deferred in the sort. func AscNetworkSize(p1Ptr, p2Ptr *SockAddr) int { p1 := *p1Ptr p2 := *p2Ptr p1Type := p1.Type() p2Type := p2.Type() // Network size operations on non-IP types make no sense if p1Type != p2Type && p1Type != TypeIP { return sortDeferDecision } ipA := p1.(IPAddr) ipB := p2.(IPAddr) return bytes.Compare([]byte(*ipA.NetIPMask()), []byte(*ipB.NetIPMask())) } // AscType is a sorting function to sort "more secure" types before // "less-secure" types. func AscType(p1Ptr, p2Ptr *SockAddr) int { p1 := *p1Ptr p2 := *p2Ptr p1Type := p1.Type() p2Type := p2.Type() switch { case p1Type < p2Type: return sortReceiverBeforeArg case p1Type == p2Type: return sortDeferDecision case p1Type > p2Type: return sortArgBeforeReceiver default: return sortDeferDecision } } // FilterByType returns two lists: a list of matched and unmatched SockAddrs func (sas SockAddrs) FilterByType(type_ SockAddrType) (matched, excluded SockAddrs) { matched = make(SockAddrs, 0, len(sas)) excluded = make(SockAddrs, 0, len(sas)) for _, sa := range sas { if sa.Type()&type_ != 0 { matched = append(matched, sa) } else { excluded = append(excluded, sa) } } return matched, excluded } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/go-sockaddr/unixsock.go ================================================ package sockaddr import ( "fmt" "strings" ) type UnixSock struct { SockAddr path string } type UnixSocks []*UnixSock // unixAttrMap is a map of the UnixSockAddr type-specific attributes. var unixAttrMap map[AttrName]func(UnixSock) string var unixAttrs []AttrName func init() { unixAttrInit() } // NewUnixSock creates an UnixSock from a string path. String can be in the // form of either URI-based string (e.g. `file:///etc/passwd`), an absolute // path (e.g. `/etc/passwd`), or a relative path (e.g. `./foo`). func NewUnixSock(s string) (ret UnixSock, err error) { ret.path = s return ret, nil } // Contains returns true if sa and us have the same path func (us UnixSock) Contains(sa SockAddr) bool { usb, ok := sa.(UnixSock) if !ok { return false } return usb.path == us.path } // CmpAddress follows the Cmp() standard protocol and returns: // // - -1 If the receiver should sort first because its name lexically sorts before arg // - 0 if the SockAddr arg is not a UnixSock, or is a UnixSock with the same path. // - 1 If the argument should sort first. func (us UnixSock) CmpAddress(sa SockAddr) int { usb, ok := sa.(UnixSock) if !ok { return sortDeferDecision } return strings.Compare(us.Path(), usb.Path()) } // CmpRFC doesn't make sense for a Unix socket, so just return defer decision func (us UnixSock) CmpRFC(rfcNum uint, sa SockAddr) int { return sortDeferDecision } // DialPacketArgs returns the arguments required to be passed to net.DialUnix() // with the `unixgram` network type. func (us UnixSock) DialPacketArgs() (network, dialArgs string) { return "unixgram", us.path } // DialStreamArgs returns the arguments required to be passed to net.DialUnix() // with the `unix` network type. func (us UnixSock) DialStreamArgs() (network, dialArgs string) { return "unix", us.path } // Equal returns true if a SockAddr is equal to the receiving UnixSock. func (us UnixSock) Equal(sa SockAddr) bool { usb, ok := sa.(UnixSock) if !ok { return false } if us.Path() != usb.Path() { return false } return true } // ListenPacketArgs returns the arguments required to be passed to // net.ListenUnixgram() with the `unixgram` network type. func (us UnixSock) ListenPacketArgs() (network, dialArgs string) { return "unixgram", us.path } // ListenStreamArgs returns the arguments required to be passed to // net.ListenUnix() with the `unix` network type. func (us UnixSock) ListenStreamArgs() (network, dialArgs string) { return "unix", us.path } // MustUnixSock is a helper method that must return an UnixSock or panic on // invalid input. func MustUnixSock(addr string) UnixSock { us, err := NewUnixSock(addr) if err != nil { panic(fmt.Sprintf("Unable to create a UnixSock from %+q: %v", addr, err)) } return us } // Path returns the given path of the UnixSock func (us UnixSock) Path() string { return us.path } // String returns the path of the UnixSock func (us UnixSock) String() string { return fmt.Sprintf("%+q", us.path) } // Type is used as a type switch and returns TypeUnix func (UnixSock) Type() SockAddrType { return TypeUnix } // UnixSockAttrs returns a list of attributes supported by the UnixSockAddr type func UnixSockAttrs() []AttrName { return unixAttrs } // UnixSockAttr returns a string representation of an attribute for the given // UnixSock. func UnixSockAttr(us UnixSock, attrName AttrName) string { fn, found := unixAttrMap[attrName] if !found { return "" } return fn(us) } // unixAttrInit is called once at init() func unixAttrInit() { // Sorted for human readability unixAttrs = []AttrName{ "path", } unixAttrMap = map[AttrName]func(us UnixSock) string{ "path": func(us UnixSock) string { return us.Path() }, } } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/golang-lru/.gitignore ================================================ # Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/golang-lru/.golangci.yml ================================================ linters: enable: - megacheck - revive - govet - unconvert - megacheck - gas - gocyclo - dupl - misspell - unparam - unused - typecheck - ineffassign - stylecheck - exportloopref - gocritic - nakedret - gosimple - prealloc fast: false disable-all: true issues: exclude-rules: - path: _test\.go linters: - dupl exclude-use-default: false ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/golang-lru/2q.go ================================================ package lru import ( "fmt" "sync" "github.com/hashicorp/golang-lru/simplelru" ) const ( // Default2QRecentRatio is the ratio of the 2Q cache dedicated // to recently added entries that have only been accessed once. Default2QRecentRatio = 0.25 // Default2QGhostEntries is the default ratio of ghost // entries kept to track entries recently evicted Default2QGhostEntries = 0.50 ) // TwoQueueCache is a thread-safe fixed size 2Q cache. // 2Q is an enhancement over the standard LRU cache // in that it tracks both frequently and recently used // entries separately. This avoids a burst in access to new // entries from evicting frequently used entries. It adds some // additional tracking overhead to the standard LRU cache, and is // computationally about 2x the cost, and adds some metadata over // head. The ARCCache is similar, but does not require setting any // parameters. type TwoQueueCache struct { size int recentSize int recent simplelru.LRUCache frequent simplelru.LRUCache recentEvict simplelru.LRUCache lock sync.RWMutex } // New2Q creates a new TwoQueueCache using the default // values for the parameters. func New2Q(size int) (*TwoQueueCache, error) { return New2QParams(size, Default2QRecentRatio, Default2QGhostEntries) } // New2QParams creates a new TwoQueueCache using the provided // parameter values. func New2QParams(size int, recentRatio, ghostRatio float64) (*TwoQueueCache, error) { if size <= 0 { return nil, fmt.Errorf("invalid size") } if recentRatio < 0.0 || recentRatio > 1.0 { return nil, fmt.Errorf("invalid recent ratio") } if ghostRatio < 0.0 || ghostRatio > 1.0 { return nil, fmt.Errorf("invalid ghost ratio") } // Determine the sub-sizes recentSize := int(float64(size) * recentRatio) evictSize := int(float64(size) * ghostRatio) // Allocate the LRUs recent, err := simplelru.NewLRU(size, nil) if err != nil { return nil, err } frequent, err := simplelru.NewLRU(size, nil) if err != nil { return nil, err } recentEvict, err := simplelru.NewLRU(evictSize, nil) if err != nil { return nil, err } // Initialize the cache c := &TwoQueueCache{ size: size, recentSize: recentSize, recent: recent, frequent: frequent, recentEvict: recentEvict, } return c, nil } // Get looks up a key's value from the cache. func (c *TwoQueueCache) Get(key interface{}) (value interface{}, ok bool) { c.lock.Lock() defer c.lock.Unlock() // Check if this is a frequent value if val, ok := c.frequent.Get(key); ok { return val, ok } // If the value is contained in recent, then we // promote it to frequent if val, ok := c.recent.Peek(key); ok { c.recent.Remove(key) c.frequent.Add(key, val) return val, ok } // No hit return nil, false } // Add adds a value to the cache. func (c *TwoQueueCache) Add(key, value interface{}) { c.lock.Lock() defer c.lock.Unlock() // Check if the value is frequently used already, // and just update the value if c.frequent.Contains(key) { c.frequent.Add(key, value) return } // Check if the value is recently used, and promote // the value into the frequent list if c.recent.Contains(key) { c.recent.Remove(key) c.frequent.Add(key, value) return } // If the value was recently evicted, add it to the // frequently used list if c.recentEvict.Contains(key) { c.ensureSpace(true) c.recentEvict.Remove(key) c.frequent.Add(key, value) return } // Add to the recently seen list c.ensureSpace(false) c.recent.Add(key, value) } // ensureSpace is used to ensure we have space in the cache func (c *TwoQueueCache) ensureSpace(recentEvict bool) { // If we have space, nothing to do recentLen := c.recent.Len() freqLen := c.frequent.Len() if recentLen+freqLen < c.size { return } // If the recent buffer is larger than // the target, evict from there if recentLen > 0 && (recentLen > c.recentSize || (recentLen == c.recentSize && !recentEvict)) { k, _, _ := c.recent.RemoveOldest() c.recentEvict.Add(k, nil) return } // Remove from the frequent list otherwise c.frequent.RemoveOldest() } // Len returns the number of items in the cache. func (c *TwoQueueCache) Len() int { c.lock.RLock() defer c.lock.RUnlock() return c.recent.Len() + c.frequent.Len() } // Keys returns a slice of the keys in the cache. // The frequently used keys are first in the returned slice. func (c *TwoQueueCache) Keys() []interface{} { c.lock.RLock() defer c.lock.RUnlock() k1 := c.frequent.Keys() k2 := c.recent.Keys() return append(k1, k2...) } // Remove removes the provided key from the cache. func (c *TwoQueueCache) Remove(key interface{}) { c.lock.Lock() defer c.lock.Unlock() if c.frequent.Remove(key) { return } if c.recent.Remove(key) { return } if c.recentEvict.Remove(key) { return } } // Purge is used to completely clear the cache. func (c *TwoQueueCache) Purge() { c.lock.Lock() defer c.lock.Unlock() c.recent.Purge() c.frequent.Purge() c.recentEvict.Purge() } // Contains is used to check if the cache contains a key // without updating recency or frequency. func (c *TwoQueueCache) Contains(key interface{}) bool { c.lock.RLock() defer c.lock.RUnlock() return c.frequent.Contains(key) || c.recent.Contains(key) } // Peek is used to inspect the cache value of a key // without updating recency or frequency. func (c *TwoQueueCache) Peek(key interface{}) (value interface{}, ok bool) { c.lock.RLock() defer c.lock.RUnlock() if val, ok := c.frequent.Peek(key); ok { return val, ok } return c.recent.Peek(key) } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/golang-lru/LICENSE ================================================ Copyright (c) 2014 HashiCorp, Inc. Mozilla Public License, version 2.0 1. Definitions 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means a. that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or b. that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: a. any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or b. any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: a. under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and b. under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: a. for any code that a Contributor has removed from Covered Software; or b. for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or c. under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: a. such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and b. You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. 6. Disclaimer of Warranty Covered Software is provided under this License on an "as is" basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer. 7. Limitation of Liability Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party's negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You. 8. Litigation Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/golang-lru/README.md ================================================ golang-lru ========== Please upgrade to github.com/hashicorp/golang-lru/v2 for all new code as v1 will not be updated anymore. The v2 version supports generics and is faster; old code can specify a specific tag, e.g. github.com/hashicorp/golang-lru/v1.0.2 for backwards compatibility. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/golang-lru/arc.go ================================================ package lru import ( "sync" "github.com/hashicorp/golang-lru/simplelru" ) // ARCCache is a thread-safe fixed size Adaptive Replacement Cache (ARC). // ARC is an enhancement over the standard LRU cache in that tracks both // frequency and recency of use. This avoids a burst in access to new // entries from evicting the frequently used older entries. It adds some // additional tracking overhead to a standard LRU cache, computationally // it is roughly 2x the cost, and the extra memory overhead is linear // with the size of the cache. ARC has been patented by IBM, but is // similar to the TwoQueueCache (2Q) which requires setting parameters. type ARCCache struct { size int // Size is the total capacity of the cache p int // P is the dynamic preference towards T1 or T2 t1 simplelru.LRUCache // T1 is the LRU for recently accessed items b1 simplelru.LRUCache // B1 is the LRU for evictions from t1 t2 simplelru.LRUCache // T2 is the LRU for frequently accessed items b2 simplelru.LRUCache // B2 is the LRU for evictions from t2 lock sync.RWMutex } // NewARC creates an ARC of the given size func NewARC(size int) (*ARCCache, error) { // Create the sub LRUs b1, err := simplelru.NewLRU(size, nil) if err != nil { return nil, err } b2, err := simplelru.NewLRU(size, nil) if err != nil { return nil, err } t1, err := simplelru.NewLRU(size, nil) if err != nil { return nil, err } t2, err := simplelru.NewLRU(size, nil) if err != nil { return nil, err } // Initialize the ARC c := &ARCCache{ size: size, p: 0, t1: t1, b1: b1, t2: t2, b2: b2, } return c, nil } // Get looks up a key's value from the cache. func (c *ARCCache) Get(key interface{}) (value interface{}, ok bool) { c.lock.Lock() defer c.lock.Unlock() // If the value is contained in T1 (recent), then // promote it to T2 (frequent) if val, ok := c.t1.Peek(key); ok { c.t1.Remove(key) c.t2.Add(key, val) return val, ok } // Check if the value is contained in T2 (frequent) if val, ok := c.t2.Get(key); ok { return val, ok } // No hit return nil, false } // Add adds a value to the cache. func (c *ARCCache) Add(key, value interface{}) { c.lock.Lock() defer c.lock.Unlock() // Check if the value is contained in T1 (recent), and potentially // promote it to frequent T2 if c.t1.Contains(key) { c.t1.Remove(key) c.t2.Add(key, value) return } // Check if the value is already in T2 (frequent) and update it if c.t2.Contains(key) { c.t2.Add(key, value) return } // Check if this value was recently evicted as part of the // recently used list if c.b1.Contains(key) { // T1 set is too small, increase P appropriately delta := 1 b1Len := c.b1.Len() b2Len := c.b2.Len() if b2Len > b1Len { delta = b2Len / b1Len } if c.p+delta >= c.size { c.p = c.size } else { c.p += delta } // Potentially need to make room in the cache if c.t1.Len()+c.t2.Len() >= c.size { c.replace(false) } // Remove from B1 c.b1.Remove(key) // Add the key to the frequently used list c.t2.Add(key, value) return } // Check if this value was recently evicted as part of the // frequently used list if c.b2.Contains(key) { // T2 set is too small, decrease P appropriately delta := 1 b1Len := c.b1.Len() b2Len := c.b2.Len() if b1Len > b2Len { delta = b1Len / b2Len } if delta >= c.p { c.p = 0 } else { c.p -= delta } // Potentially need to make room in the cache if c.t1.Len()+c.t2.Len() >= c.size { c.replace(true) } // Remove from B2 c.b2.Remove(key) // Add the key to the frequently used list c.t2.Add(key, value) return } // Potentially need to make room in the cache if c.t1.Len()+c.t2.Len() >= c.size { c.replace(false) } // Keep the size of the ghost buffers trim if c.b1.Len() > c.size-c.p { c.b1.RemoveOldest() } if c.b2.Len() > c.p { c.b2.RemoveOldest() } // Add to the recently seen list c.t1.Add(key, value) } // replace is used to adaptively evict from either T1 or T2 // based on the current learned value of P func (c *ARCCache) replace(b2ContainsKey bool) { t1Len := c.t1.Len() if t1Len > 0 && (t1Len > c.p || (t1Len == c.p && b2ContainsKey)) { k, _, ok := c.t1.RemoveOldest() if ok { c.b1.Add(k, nil) } } else { k, _, ok := c.t2.RemoveOldest() if ok { c.b2.Add(k, nil) } } } // Len returns the number of cached entries func (c *ARCCache) Len() int { c.lock.RLock() defer c.lock.RUnlock() return c.t1.Len() + c.t2.Len() } // Keys returns all the cached keys func (c *ARCCache) Keys() []interface{} { c.lock.RLock() defer c.lock.RUnlock() k1 := c.t1.Keys() k2 := c.t2.Keys() return append(k1, k2...) } // Remove is used to purge a key from the cache func (c *ARCCache) Remove(key interface{}) { c.lock.Lock() defer c.lock.Unlock() if c.t1.Remove(key) { return } if c.t2.Remove(key) { return } if c.b1.Remove(key) { return } if c.b2.Remove(key) { return } } // Purge is used to clear the cache func (c *ARCCache) Purge() { c.lock.Lock() defer c.lock.Unlock() c.t1.Purge() c.t2.Purge() c.b1.Purge() c.b2.Purge() } // Contains is used to check if the cache contains a key // without updating recency or frequency. func (c *ARCCache) Contains(key interface{}) bool { c.lock.RLock() defer c.lock.RUnlock() return c.t1.Contains(key) || c.t2.Contains(key) } // Peek is used to inspect the cache value of a key // without updating recency or frequency. func (c *ARCCache) Peek(key interface{}) (value interface{}, ok bool) { c.lock.RLock() defer c.lock.RUnlock() if val, ok := c.t1.Peek(key); ok { return val, ok } return c.t2.Peek(key) } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/golang-lru/doc.go ================================================ // Package lru provides three different LRU caches of varying sophistication. // // Cache is a simple LRU cache. It is based on the // LRU implementation in groupcache: // https://github.com/golang/groupcache/tree/master/lru // // TwoQueueCache tracks frequently used and recently used entries separately. // This avoids a burst of accesses from taking out frequently used entries, // at the cost of about 2x computational overhead and some extra bookkeeping. // // ARCCache is an adaptive replacement cache. It tracks recent evictions as // well as recent usage in both the frequent and recent caches. Its // computational overhead is comparable to TwoQueueCache, but the memory // overhead is linear with the size of the cache. // // ARC has been patented by IBM, so do not use it if that is problematic for // your program. // // All caches in this package take locks while operating, and are therefore // thread-safe for consumers. package lru ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/golang-lru/lru.go ================================================ package lru import ( "sync" "github.com/hashicorp/golang-lru/simplelru" ) const ( // DefaultEvictedBufferSize defines the default buffer size to store evicted key/val DefaultEvictedBufferSize = 16 ) // Cache is a thread-safe fixed size LRU cache. type Cache struct { lru *simplelru.LRU evictedKeys, evictedVals []interface{} onEvictedCB func(k, v interface{}) lock sync.RWMutex } // New creates an LRU of the given size. func New(size int) (*Cache, error) { return NewWithEvict(size, nil) } // NewWithEvict constructs a fixed size cache with the given eviction // callback. func NewWithEvict(size int, onEvicted func(key, value interface{})) (c *Cache, err error) { // create a cache with default settings c = &Cache{ onEvictedCB: onEvicted, } if onEvicted != nil { c.initEvictBuffers() onEvicted = c.onEvicted } c.lru, err = simplelru.NewLRU(size, onEvicted) return } func (c *Cache) initEvictBuffers() { c.evictedKeys = make([]interface{}, 0, DefaultEvictedBufferSize) c.evictedVals = make([]interface{}, 0, DefaultEvictedBufferSize) } // onEvicted save evicted key/val and sent in externally registered callback // outside of critical section func (c *Cache) onEvicted(k, v interface{}) { c.evictedKeys = append(c.evictedKeys, k) c.evictedVals = append(c.evictedVals, v) } // Purge is used to completely clear the cache. func (c *Cache) Purge() { var ks, vs []interface{} c.lock.Lock() c.lru.Purge() if c.onEvictedCB != nil && len(c.evictedKeys) > 0 { ks, vs = c.evictedKeys, c.evictedVals c.initEvictBuffers() } c.lock.Unlock() // invoke callback outside of critical section if c.onEvictedCB != nil { for i := 0; i < len(ks); i++ { c.onEvictedCB(ks[i], vs[i]) } } } // Add adds a value to the cache. Returns true if an eviction occurred. func (c *Cache) Add(key, value interface{}) (evicted bool) { var k, v interface{} c.lock.Lock() evicted = c.lru.Add(key, value) if c.onEvictedCB != nil && evicted { k, v = c.evictedKeys[0], c.evictedVals[0] c.evictedKeys, c.evictedVals = c.evictedKeys[:0], c.evictedVals[:0] } c.lock.Unlock() if c.onEvictedCB != nil && evicted { c.onEvictedCB(k, v) } return } // Get looks up a key's value from the cache. func (c *Cache) Get(key interface{}) (value interface{}, ok bool) { c.lock.Lock() value, ok = c.lru.Get(key) c.lock.Unlock() return value, ok } // Contains checks if a key is in the cache, without updating the // recent-ness or deleting it for being stale. func (c *Cache) Contains(key interface{}) bool { c.lock.RLock() containKey := c.lru.Contains(key) c.lock.RUnlock() return containKey } // Peek returns the key value (or undefined if not found) without updating // the "recently used"-ness of the key. func (c *Cache) Peek(key interface{}) (value interface{}, ok bool) { c.lock.RLock() value, ok = c.lru.Peek(key) c.lock.RUnlock() return value, ok } // ContainsOrAdd checks if a key is in the cache without updating the // recent-ness or deleting it for being stale, and if not, adds the value. // Returns whether found and whether an eviction occurred. func (c *Cache) ContainsOrAdd(key, value interface{}) (ok, evicted bool) { var k, v interface{} c.lock.Lock() if c.lru.Contains(key) { c.lock.Unlock() return true, false } evicted = c.lru.Add(key, value) if c.onEvictedCB != nil && evicted { k, v = c.evictedKeys[0], c.evictedVals[0] c.evictedKeys, c.evictedVals = c.evictedKeys[:0], c.evictedVals[:0] } c.lock.Unlock() if c.onEvictedCB != nil && evicted { c.onEvictedCB(k, v) } return false, evicted } // PeekOrAdd checks if a key is in the cache without updating the // recent-ness or deleting it for being stale, and if not, adds the value. // Returns whether found and whether an eviction occurred. func (c *Cache) PeekOrAdd(key, value interface{}) (previous interface{}, ok, evicted bool) { var k, v interface{} c.lock.Lock() previous, ok = c.lru.Peek(key) if ok { c.lock.Unlock() return previous, true, false } evicted = c.lru.Add(key, value) if c.onEvictedCB != nil && evicted { k, v = c.evictedKeys[0], c.evictedVals[0] c.evictedKeys, c.evictedVals = c.evictedKeys[:0], c.evictedVals[:0] } c.lock.Unlock() if c.onEvictedCB != nil && evicted { c.onEvictedCB(k, v) } return nil, false, evicted } // Remove removes the provided key from the cache. func (c *Cache) Remove(key interface{}) (present bool) { var k, v interface{} c.lock.Lock() present = c.lru.Remove(key) if c.onEvictedCB != nil && present { k, v = c.evictedKeys[0], c.evictedVals[0] c.evictedKeys, c.evictedVals = c.evictedKeys[:0], c.evictedVals[:0] } c.lock.Unlock() if c.onEvictedCB != nil && present { c.onEvictedCB(k, v) } return } // Resize changes the cache size. func (c *Cache) Resize(size int) (evicted int) { var ks, vs []interface{} c.lock.Lock() evicted = c.lru.Resize(size) if c.onEvictedCB != nil && evicted > 0 { ks, vs = c.evictedKeys, c.evictedVals c.initEvictBuffers() } c.lock.Unlock() if c.onEvictedCB != nil && evicted > 0 { for i := 0; i < len(ks); i++ { c.onEvictedCB(ks[i], vs[i]) } } return evicted } // RemoveOldest removes the oldest item from the cache. func (c *Cache) RemoveOldest() (key, value interface{}, ok bool) { var k, v interface{} c.lock.Lock() key, value, ok = c.lru.RemoveOldest() if c.onEvictedCB != nil && ok { k, v = c.evictedKeys[0], c.evictedVals[0] c.evictedKeys, c.evictedVals = c.evictedKeys[:0], c.evictedVals[:0] } c.lock.Unlock() if c.onEvictedCB != nil && ok { c.onEvictedCB(k, v) } return } // GetOldest returns the oldest entry func (c *Cache) GetOldest() (key, value interface{}, ok bool) { c.lock.RLock() key, value, ok = c.lru.GetOldest() c.lock.RUnlock() return } // Keys returns a slice of the keys in the cache, from oldest to newest. func (c *Cache) Keys() []interface{} { c.lock.RLock() keys := c.lru.Keys() c.lock.RUnlock() return keys } // Len returns the number of items in the cache. func (c *Cache) Len() int { c.lock.RLock() length := c.lru.Len() c.lock.RUnlock() return length } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/golang-lru/simplelru/lru.go ================================================ package simplelru import ( "container/list" "errors" ) // EvictCallback is used to get a callback when a cache entry is evicted type EvictCallback func(key interface{}, value interface{}) // LRU implements a non-thread safe fixed size LRU cache type LRU struct { size int evictList *list.List items map[interface{}]*list.Element onEvict EvictCallback } // entry is used to hold a value in the evictList type entry struct { key interface{} value interface{} } // NewLRU constructs an LRU of the given size func NewLRU(size int, onEvict EvictCallback) (*LRU, error) { if size <= 0 { return nil, errors.New("must provide a positive size") } c := &LRU{ size: size, evictList: list.New(), items: make(map[interface{}]*list.Element), onEvict: onEvict, } return c, nil } // Purge is used to completely clear the cache. func (c *LRU) Purge() { for k, v := range c.items { if c.onEvict != nil { c.onEvict(k, v.Value.(*entry).value) } delete(c.items, k) } c.evictList.Init() } // Add adds a value to the cache. Returns true if an eviction occurred. func (c *LRU) Add(key, value interface{}) (evicted bool) { // Check for existing item if ent, ok := c.items[key]; ok { c.evictList.MoveToFront(ent) ent.Value.(*entry).value = value return false } // Add new item ent := &entry{key, value} entry := c.evictList.PushFront(ent) c.items[key] = entry evict := c.evictList.Len() > c.size // Verify size not exceeded if evict { c.removeOldest() } return evict } // Get looks up a key's value from the cache. func (c *LRU) Get(key interface{}) (value interface{}, ok bool) { if ent, ok := c.items[key]; ok { c.evictList.MoveToFront(ent) if ent.Value.(*entry) == nil { return nil, false } return ent.Value.(*entry).value, true } return } // Contains checks if a key is in the cache, without updating the recent-ness // or deleting it for being stale. func (c *LRU) Contains(key interface{}) (ok bool) { _, ok = c.items[key] return ok } // Peek returns the key value (or undefined if not found) without updating // the "recently used"-ness of the key. func (c *LRU) Peek(key interface{}) (value interface{}, ok bool) { var ent *list.Element if ent, ok = c.items[key]; ok { return ent.Value.(*entry).value, true } return nil, ok } // Remove removes the provided key from the cache, returning if the // key was contained. func (c *LRU) Remove(key interface{}) (present bool) { if ent, ok := c.items[key]; ok { c.removeElement(ent) return true } return false } // RemoveOldest removes the oldest item from the cache. func (c *LRU) RemoveOldest() (key, value interface{}, ok bool) { ent := c.evictList.Back() if ent != nil { c.removeElement(ent) kv := ent.Value.(*entry) return kv.key, kv.value, true } return nil, nil, false } // GetOldest returns the oldest entry func (c *LRU) GetOldest() (key, value interface{}, ok bool) { ent := c.evictList.Back() if ent != nil { kv := ent.Value.(*entry) return kv.key, kv.value, true } return nil, nil, false } // Keys returns a slice of the keys in the cache, from oldest to newest. func (c *LRU) Keys() []interface{} { keys := make([]interface{}, len(c.items)) i := 0 for ent := c.evictList.Back(); ent != nil; ent = ent.Prev() { keys[i] = ent.Value.(*entry).key i++ } return keys } // Len returns the number of items in the cache. func (c *LRU) Len() int { return c.evictList.Len() } // Resize changes the cache size. func (c *LRU) Resize(size int) (evicted int) { diff := c.Len() - size if diff < 0 { diff = 0 } for i := 0; i < diff; i++ { c.removeOldest() } c.size = size return diff } // removeOldest removes the oldest item from the cache. func (c *LRU) removeOldest() { ent := c.evictList.Back() if ent != nil { c.removeElement(ent) } } // removeElement is used to remove a given list element from the cache func (c *LRU) removeElement(e *list.Element) { c.evictList.Remove(e) kv := e.Value.(*entry) delete(c.items, kv.key) if c.onEvict != nil { c.onEvict(kv.key, kv.value) } } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/golang-lru/simplelru/lru_interface.go ================================================ // Package simplelru provides simple LRU implementation based on build-in container/list. package simplelru // LRUCache is the interface for simple LRU cache. type LRUCache interface { // Adds a value to the cache, returns true if an eviction occurred and // updates the "recently used"-ness of the key. Add(key, value interface{}) bool // Returns key's value from the cache and // updates the "recently used"-ness of the key. #value, isFound Get(key interface{}) (value interface{}, ok bool) // Checks if a key exists in cache without updating the recent-ness. Contains(key interface{}) (ok bool) // Returns key's value without updating the "recently used"-ness of the key. Peek(key interface{}) (value interface{}, ok bool) // Removes a key from the cache. Remove(key interface{}) bool // Removes the oldest entry from cache. RemoveOldest() (interface{}, interface{}, bool) // Returns the oldest entry from the cache. #key, value, isFound GetOldest() (interface{}, interface{}, bool) // Returns a slice of the keys in the cache, from oldest to newest. Keys() []interface{} // Returns the number of items in the cache. Len() int // Clears all cache entries. Purge() // Resizes cache, returning number evicted Resize(int) int } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/golang-lru/testing.go ================================================ package lru import ( "crypto/rand" "math" "math/big" "testing" ) func getRand(tb testing.TB) int64 { out, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64)) if err != nil { tb.Fatal(err) } return out.Int64() } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/.gitignore ================================================ y.output # ignore intellij files .idea *.iml *.ipr *.iws *.test ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/.travis.yml ================================================ sudo: false language: go go: - 1.x - tip branches: only: - master script: make test ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/LICENSE ================================================ Mozilla Public License, version 2.0 1. Definitions 1.1. “Contributor” means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. “Contributor Version” means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor’s Contribution. 1.3. “Contribution” means Covered Software of a particular Contributor. 1.4. “Covered Software” means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. “Incompatible With Secondary Licenses” means a. that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or b. that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. “Executable Form” means any form of the work other than Source Code Form. 1.7. “Larger Work” means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. “License” means this document. 1.9. “Licensable” means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. “Modifications” means any of the following: a. any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or b. any new file in Source Code Form that contains any Covered Software. 1.11. “Patent Claims” of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. “Secondary License” means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. “Source Code Form” means the form of the work preferred for making modifications. 1.14. “You” (or “Your”) means an individual or a legal entity exercising rights under this License. For legal entities, “You” includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, “control” means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: a. under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and b. under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: a. for any code that a Contributor has removed from Covered Software; or b. for infringements caused by: (i) Your and any other third party’s modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or c. under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients’ rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: a. such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and b. You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients’ rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. 6. Disclaimer of Warranty Covered Software is provided under this License on an “as is” basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer. 7. Limitation of Liability Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party’s negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You. 8. Litigation Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party’s ability to bring cross-claims or counter-claims. 9. Miscellaneous This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - “Incompatible With Secondary Licenses” Notice This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/Makefile ================================================ TEST?=./... default: test fmt: generate go fmt ./... test: generate go get -t ./... go test $(TEST) $(TESTARGS) generate: go generate ./... updatedeps: go get -u golang.org/x/tools/cmd/stringer .PHONY: default generate test updatedeps ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/README.md ================================================ # HCL [![GoDoc](https://godoc.org/github.com/hashicorp/hcl?status.png)](https://godoc.org/github.com/hashicorp/hcl) [![Build Status](https://travis-ci.org/hashicorp/hcl.svg?branch=master)](https://travis-ci.org/hashicorp/hcl) HCL (HashiCorp Configuration Language) is a configuration language built by HashiCorp. The goal of HCL is to build a structured configuration language that is both human and machine friendly for use with command-line tools, but specifically targeted towards DevOps tools, servers, etc. HCL is also fully JSON compatible. That is, JSON can be used as completely valid input to a system expecting HCL. This helps makes systems interoperable with other systems. HCL is heavily inspired by [libucl](https://github.com/vstakhov/libucl), nginx configuration, and others similar. ## Why? A common question when viewing HCL is to ask the question: why not JSON, YAML, etc.? Prior to HCL, the tools we built at [HashiCorp](http://www.hashicorp.com) used a variety of configuration languages from full programming languages such as Ruby to complete data structure languages such as JSON. What we learned is that some people wanted human-friendly configuration languages and some people wanted machine-friendly languages. JSON fits a nice balance in this, but is fairly verbose and most importantly doesn't support comments. With YAML, we found that beginners had a really hard time determining what the actual structure was, and ended up guessing more often than not whether to use a hyphen, colon, etc. in order to represent some configuration key. Full programming languages such as Ruby enable complex behavior a configuration language shouldn't usually allow, and also forces people to learn some set of Ruby. Because of this, we decided to create our own configuration language that is JSON-compatible. Our configuration language (HCL) is designed to be written and modified by humans. The API for HCL allows JSON as an input so that it is also machine-friendly (machines can generate JSON instead of trying to generate HCL). Our goal with HCL is not to alienate other configuration languages. It is instead to provide HCL as a specialized language for our tools, and JSON as the interoperability layer. ## Syntax For a complete grammar, please see the parser itself. A high-level overview of the syntax and grammar is listed here. * Single line comments start with `#` or `//` * Multi-line comments are wrapped in `/*` and `*/`. Nested block comments are not allowed. A multi-line comment (also known as a block comment) terminates at the first `*/` found. * Values are assigned with the syntax `key = value` (whitespace doesn't matter). The value can be any primitive: a string, number, boolean, object, or list. * Strings are double-quoted and can contain any UTF-8 characters. Example: `"Hello, World"` * Multi-line strings start with `<- echo %Path% go version go env go get -t ./... build_script: - cmd: go test -v ./... ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/decoder.go ================================================ package hcl import ( "errors" "fmt" "reflect" "sort" "strconv" "strings" "github.com/hashicorp/hcl/hcl/ast" "github.com/hashicorp/hcl/hcl/parser" "github.com/hashicorp/hcl/hcl/token" ) // This is the tag to use with structures to have settings for HCL const tagName = "hcl" var ( // nodeType holds a reference to the type of ast.Node nodeType reflect.Type = findNodeType() ) // Unmarshal accepts a byte slice as input and writes the // data to the value pointed to by v. func Unmarshal(bs []byte, v interface{}) error { root, err := parse(bs, false) if err != nil { return err } return DecodeObject(v, root) } // UnmarshalErrorOnDuplicates accepts a byte slice as input and writes the // data to the value pointed to by v but errors on duplicate attribute key. func UnmarshalErrorOnDuplicates(bs []byte, v interface{}) error { root, err := parse(bs, true) if err != nil { return err } return DecodeObject(v, root) } // Decode reads the given input and decodes it into the structure // given by `out`. func Decode(out interface{}, in string) error { return decode(out, in, false) } // DecodeErrorOnDuplicates reads the given input and decodes it into the structure but errrors on duplicate attribute key // given by `out`. func DecodeErrorOnDuplicates(out interface{}, in string) error { return decode(out, in, true) } // decode reads the given input and decodes it into the structure given by `out`. // takes in a boolean to determine if it should error on duplicate attribute func decode(out interface{}, in string, errorOnDuplicateAtributes bool) error { obj, err := parse([]byte(in), errorOnDuplicateAtributes) if err != nil { return err } return DecodeObject(out, obj) } // DecodeObject is a lower-level version of Decode. It decodes a // raw Object into the given output. func DecodeObject(out interface{}, n ast.Node) error { val := reflect.ValueOf(out) if val.Kind() != reflect.Ptr { return errors.New("result must be a pointer") } // If we have the file, we really decode the root node if f, ok := n.(*ast.File); ok { n = f.Node } var d decoder return d.decode("root", n, val.Elem()) } type decoder struct { stack []reflect.Kind } func (d *decoder) decode(name string, node ast.Node, result reflect.Value) error { k := result // If we have an interface with a valid value, we use that // for the check. if result.Kind() == reflect.Interface { elem := result.Elem() if elem.IsValid() { k = elem } } // Push current onto stack unless it is an interface. if k.Kind() != reflect.Interface { d.stack = append(d.stack, k.Kind()) // Schedule a pop defer func() { d.stack = d.stack[:len(d.stack)-1] }() } switch k.Kind() { case reflect.Bool: return d.decodeBool(name, node, result) case reflect.Float32, reflect.Float64: return d.decodeFloat(name, node, result) case reflect.Int, reflect.Int32, reflect.Int64: return d.decodeInt(name, node, result) case reflect.Interface: // When we see an interface, we make our own thing return d.decodeInterface(name, node, result) case reflect.Map: return d.decodeMap(name, node, result) case reflect.Ptr: return d.decodePtr(name, node, result) case reflect.Slice: return d.decodeSlice(name, node, result) case reflect.String: return d.decodeString(name, node, result) case reflect.Struct: return d.decodeStruct(name, node, result) default: return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: unknown kind to decode into: %s", name, k.Kind()), } } } func (d *decoder) decodeBool(name string, node ast.Node, result reflect.Value) error { switch n := node.(type) { case *ast.LiteralType: if n.Token.Type == token.BOOL { v, err := strconv.ParseBool(n.Token.Text) if err != nil { return err } result.Set(reflect.ValueOf(v)) return nil } } return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: unknown type %T", name, node), } } func (d *decoder) decodeFloat(name string, node ast.Node, result reflect.Value) error { switch n := node.(type) { case *ast.LiteralType: if n.Token.Type == token.FLOAT || n.Token.Type == token.NUMBER { v, err := strconv.ParseFloat(n.Token.Text, 64) if err != nil { return err } result.Set(reflect.ValueOf(v).Convert(result.Type())) return nil } } return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: unknown type %T", name, node), } } func (d *decoder) decodeInt(name string, node ast.Node, result reflect.Value) error { switch n := node.(type) { case *ast.LiteralType: switch n.Token.Type { case token.NUMBER: v, err := strconv.ParseInt(n.Token.Text, 0, 0) if err != nil { return err } if result.Kind() == reflect.Interface { result.Set(reflect.ValueOf(int(v))) } else { result.SetInt(v) } return nil case token.STRING: v, err := strconv.ParseInt(n.Token.Value().(string), 0, 0) if err != nil { return err } if result.Kind() == reflect.Interface { result.Set(reflect.ValueOf(int(v))) } else { result.SetInt(v) } return nil } } return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: unknown type %T", name, node), } } func (d *decoder) decodeInterface(name string, node ast.Node, result reflect.Value) error { // When we see an ast.Node, we retain the value to enable deferred decoding. // Very useful in situations where we want to preserve ast.Node information // like Pos if result.Type() == nodeType && result.CanSet() { result.Set(reflect.ValueOf(node)) return nil } var set reflect.Value redecode := true // For testing types, ObjectType should just be treated as a list. We // set this to a temporary var because we want to pass in the real node. testNode := node if ot, ok := node.(*ast.ObjectType); ok { testNode = ot.List } switch n := testNode.(type) { case *ast.ObjectList: // If we're at the root or we're directly within a slice, then we // decode objects into map[string]interface{}, otherwise we decode // them into lists. if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice { var temp map[string]interface{} tempVal := reflect.ValueOf(temp) result := reflect.MakeMap( reflect.MapOf( reflect.TypeOf(""), tempVal.Type().Elem())) set = result } else { var temp []map[string]interface{} tempVal := reflect.ValueOf(temp) result := reflect.MakeSlice( reflect.SliceOf(tempVal.Type().Elem()), 0, len(n.Items)) set = result } case *ast.ObjectType: // If we're at the root or we're directly within a slice, then we // decode objects into map[string]interface{}, otherwise we decode // them into lists. if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice { var temp map[string]interface{} tempVal := reflect.ValueOf(temp) result := reflect.MakeMap( reflect.MapOf( reflect.TypeOf(""), tempVal.Type().Elem())) set = result } else { var temp []map[string]interface{} tempVal := reflect.ValueOf(temp) result := reflect.MakeSlice( reflect.SliceOf(tempVal.Type().Elem()), 0, 1) set = result } case *ast.ListType: var temp []interface{} tempVal := reflect.ValueOf(temp) result := reflect.MakeSlice( reflect.SliceOf(tempVal.Type().Elem()), 0, 0) set = result case *ast.LiteralType: switch n.Token.Type { case token.BOOL: var result bool set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) case token.FLOAT: var result float64 set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) case token.NUMBER: var result int set = reflect.Indirect(reflect.New(reflect.TypeOf(result))) case token.STRING, token.HEREDOC: set = reflect.Indirect(reflect.New(reflect.TypeOf(""))) default: return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: cannot decode into interface: %T", name, node), } } default: return fmt.Errorf( "%s: cannot decode into interface: %T", name, node) } // Set the result to what its supposed to be, then reset // result so we don't reflect into this method anymore. result.Set(set) if redecode { // Revisit the node so that we can use the newly instantiated // thing and populate it. if err := d.decode(name, node, result); err != nil { return err } } return nil } func (d *decoder) decodeMap(name string, node ast.Node, result reflect.Value) error { if item, ok := node.(*ast.ObjectItem); ok { node = &ast.ObjectList{Items: []*ast.ObjectItem{item}} } if ot, ok := node.(*ast.ObjectType); ok { node = ot.List } n, ok := node.(*ast.ObjectList) if !ok { return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: not an object type for map (%T)", name, node), } } // If we have an interface, then we can address the interface, // but not the slice itself, so get the element but set the interface set := result if result.Kind() == reflect.Interface { result = result.Elem() } resultType := result.Type() resultElemType := resultType.Elem() resultKeyType := resultType.Key() if resultKeyType.Kind() != reflect.String { return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: map must have string keys", name), } } // Make a map if it is nil resultMap := result if result.IsNil() { resultMap = reflect.MakeMap( reflect.MapOf(resultKeyType, resultElemType)) } // Go through each element and decode it. done := make(map[string]struct{}) for _, item := range n.Items { if item.Val == nil { continue } // github.com/hashicorp/terraform/issue/5740 if len(item.Keys) == 0 { return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: map must have string keys", name), } } // Get the key we're dealing with, which is the first item keyStr := item.Keys[0].Token.Value().(string) // If we've already processed this key, then ignore it if _, ok := done[keyStr]; ok { continue } // Determine the value. If we have more than one key, then we // get the objectlist of only these keys. itemVal := item.Val if len(item.Keys) > 1 { itemVal = n.Filter(keyStr) done[keyStr] = struct{}{} } // Make the field name fieldName := fmt.Sprintf("%s.%s", name, keyStr) // Get the key/value as reflection values key := reflect.ValueOf(keyStr) val := reflect.Indirect(reflect.New(resultElemType)) // If we have a pre-existing value in the map, use that oldVal := resultMap.MapIndex(key) if oldVal.IsValid() { val.Set(oldVal) } // Decode! if err := d.decode(fieldName, itemVal, val); err != nil { return err } // Set the value on the map resultMap.SetMapIndex(key, val) } // Set the final map if we can set.Set(resultMap) return nil } func (d *decoder) decodePtr(name string, node ast.Node, result reflect.Value) error { // if pointer is not nil, decode into existing value if !result.IsNil() { return d.decode(name, node, result.Elem()) } // Create an element of the concrete (non pointer) type and decode // into that. Then set the value of the pointer to this type. resultType := result.Type() resultElemType := resultType.Elem() val := reflect.New(resultElemType) if err := d.decode(name, node, reflect.Indirect(val)); err != nil { return err } result.Set(val) return nil } func (d *decoder) decodeSlice(name string, node ast.Node, result reflect.Value) error { // If we have an interface, then we can address the interface, // but not the slice itself, so get the element but set the interface set := result if result.Kind() == reflect.Interface { result = result.Elem() } // Create the slice if it isn't nil resultType := result.Type() resultElemType := resultType.Elem() if result.IsNil() { resultSliceType := reflect.SliceOf(resultElemType) result = reflect.MakeSlice( resultSliceType, 0, 0) } // Figure out the items we'll be copying into the slice var items []ast.Node switch n := node.(type) { case *ast.ObjectList: items = make([]ast.Node, len(n.Items)) for i, item := range n.Items { items[i] = item } case *ast.ObjectType: items = []ast.Node{n} case *ast.ListType: items = n.List default: return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("unknown slice type: %T", node), } } for i, item := range items { fieldName := fmt.Sprintf("%s[%d]", name, i) // Decode val := reflect.Indirect(reflect.New(resultElemType)) // if item is an object that was decoded from ambiguous JSON and // flattened, make sure it's expanded if it needs to decode into a // defined structure. item := expandObject(item, val) if err := d.decode(fieldName, item, val); err != nil { return err } // Append it onto the slice result = reflect.Append(result, val) } set.Set(result) return nil } // expandObject detects if an ambiguous JSON object was flattened to a List which // should be decoded into a struct, and expands the ast to properly deocode. func expandObject(node ast.Node, result reflect.Value) ast.Node { item, ok := node.(*ast.ObjectItem) if !ok { return node } elemType := result.Type() // our target type must be a struct switch elemType.Kind() { case reflect.Ptr: switch elemType.Elem().Kind() { case reflect.Struct: //OK default: return node } case reflect.Struct: //OK default: return node } // A list value will have a key and field name. If it had more fields, // it wouldn't have been flattened. if len(item.Keys) != 2 { return node } keyToken := item.Keys[0].Token item.Keys = item.Keys[1:] // we need to un-flatten the ast enough to decode newNode := &ast.ObjectItem{ Keys: []*ast.ObjectKey{ { Token: keyToken, }, }, Val: &ast.ObjectType{ List: &ast.ObjectList{ Items: []*ast.ObjectItem{item}, }, }, } return newNode } func (d *decoder) decodeString(name string, node ast.Node, result reflect.Value) error { switch n := node.(type) { case *ast.LiteralType: switch n.Token.Type { case token.NUMBER: result.Set(reflect.ValueOf(n.Token.Text).Convert(result.Type())) return nil case token.STRING, token.HEREDOC: result.Set(reflect.ValueOf(n.Token.Value()).Convert(result.Type())) return nil } } return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: unknown type for string %T", name, node), } } func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value) error { var item *ast.ObjectItem if it, ok := node.(*ast.ObjectItem); ok { item = it node = it.Val } if ot, ok := node.(*ast.ObjectType); ok { node = ot.List } // Handle the special case where the object itself is a literal. Previously // the yacc parser would always ensure top-level elements were arrays. The new // parser does not make the same guarantees, thus we need to convert any // top-level literal elements into a list. if _, ok := node.(*ast.LiteralType); ok && item != nil { node = &ast.ObjectList{Items: []*ast.ObjectItem{item}} } list, ok := node.(*ast.ObjectList) if !ok { return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: not an object type for struct (%T)", name, node), } } // This slice will keep track of all the structs we'll be decoding. // There can be more than one struct if there are embedded structs // that are squashed. structs := make([]reflect.Value, 1, 5) structs[0] = result // Compile the list of all the fields that we're going to be decoding // from all the structs. type field struct { field reflect.StructField val reflect.Value } fields := []field{} for len(structs) > 0 { structVal := structs[0] structs = structs[1:] structType := structVal.Type() for i := 0; i < structType.NumField(); i++ { fieldType := structType.Field(i) tagParts := strings.Split(fieldType.Tag.Get(tagName), ",") // Ignore fields with tag name "-" if tagParts[0] == "-" { continue } if fieldType.Anonymous { fieldKind := fieldType.Type.Kind() if fieldKind != reflect.Struct { return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: unsupported type to struct: %s", fieldType.Name, fieldKind), } } // We have an embedded field. We "squash" the fields down // if specified in the tag. squash := false for _, tag := range tagParts[1:] { if tag == "squash" { squash = true break } } if squash { structs = append( structs, result.FieldByName(fieldType.Name)) continue } } // Normal struct field, store it away fields = append(fields, field{fieldType, structVal.Field(i)}) } } usedKeys := make(map[string]struct{}) decodedFields := make([]string, 0, len(fields)) decodedFieldsVal := make([]reflect.Value, 0) unusedKeysVal := make([]reflect.Value, 0) // fill unusedNodeKeys with keys from the AST // a slice because we have to do equals case fold to match Filter unusedNodeKeys := make(map[string][]token.Pos, 0) for i, item := range list.Items { for _, k := range item.Keys { // isNestedJSON returns true for e.g. bar in // { "foo": { "bar": {...} } } // This isn't an unused node key, so we want to skip it isNestedJSON := i > 0 && len(item.Keys) > 1 if !isNestedJSON && (k.Token.JSON || k.Token.Type == token.IDENT) { fn := k.Token.Value().(string) sl := unusedNodeKeys[fn] unusedNodeKeys[fn] = append(sl, k.Token.Pos) } } } for _, f := range fields { field, fieldValue := f.field, f.val if !fieldValue.IsValid() { // This should never happen panic("field is not valid") } // If we can't set the field, then it is unexported or something, // and we just continue onwards. if !fieldValue.CanSet() { continue } fieldName := field.Name tagValue := field.Tag.Get(tagName) tagParts := strings.SplitN(tagValue, ",", 2) if len(tagParts) >= 2 { switch tagParts[1] { case "decodedFields": decodedFieldsVal = append(decodedFieldsVal, fieldValue) continue case "key": if item == nil { return &parser.PosError{ Pos: node.Pos(), Err: fmt.Errorf("%s: %s asked for 'key', impossible", name, fieldName), } } fieldValue.SetString(item.Keys[0].Token.Value().(string)) continue case "unusedKeyPositions": unusedKeysVal = append(unusedKeysVal, fieldValue) continue } } if tagParts[0] != "" { fieldName = tagParts[0] } // Determine the element we'll use to decode. If it is a single // match (only object with the field), then we decode it exactly. // If it is a prefix match, then we decode the matches. filter := list.Filter(fieldName) prefixMatches := filter.Children() matches := filter.Elem() if len(matches.Items) == 0 && len(prefixMatches.Items) == 0 { continue } // Track the used keys usedKeys[fieldName] = struct{}{} unusedNodeKeys = removeCaseFold(unusedNodeKeys, fieldName) // Create the field name and decode. We range over the elements // because we actually want the value. fieldName = fmt.Sprintf("%s.%s", name, fieldName) if len(prefixMatches.Items) > 0 { if err := d.decode(fieldName, prefixMatches, fieldValue); err != nil { return err } } for _, match := range matches.Items { var decodeNode ast.Node = match.Val if ot, ok := decodeNode.(*ast.ObjectType); ok { decodeNode = &ast.ObjectList{Items: ot.List.Items} } if err := d.decode(fieldName, decodeNode, fieldValue); err != nil { return err } } decodedFields = append(decodedFields, field.Name) } if len(decodedFieldsVal) > 0 { // Sort it so that it is deterministic sort.Strings(decodedFields) for _, v := range decodedFieldsVal { v.Set(reflect.ValueOf(decodedFields)) } } if len(unusedNodeKeys) > 0 { // like decodedFields, populated the unusedKeys field(s) for _, v := range unusedKeysVal { v.Set(reflect.ValueOf(unusedNodeKeys)) } } return nil } // findNodeType returns the type of ast.Node func findNodeType() reflect.Type { var nodeContainer struct { Node ast.Node } value := reflect.ValueOf(nodeContainer).FieldByName("Node") return value.Type() } func removeCaseFold(xs map[string][]token.Pos, y string) map[string][]token.Pos { var toDel []string for i := range xs { if strings.EqualFold(i, y) { toDel = append(toDel, i) } } for _, i := range toDel { delete(xs, i) } return xs } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/hcl/ast/ast.go ================================================ // Package ast declares the types used to represent syntax trees for HCL // (HashiCorp Configuration Language) package ast import ( "fmt" "strings" "github.com/hashicorp/hcl/hcl/token" ) // Node is an element in the abstract syntax tree. type Node interface { node() Pos() token.Pos } func (File) node() {} func (ObjectList) node() {} func (ObjectKey) node() {} func (ObjectItem) node() {} func (Comment) node() {} func (CommentGroup) node() {} func (ObjectType) node() {} func (LiteralType) node() {} func (ListType) node() {} var unknownPos token.Pos // File represents a single HCL file type File struct { Node Node // usually a *ObjectList Comments []*CommentGroup // list of all comments in the source } func (f *File) Pos() token.Pos { return f.Node.Pos() } // ObjectList represents a list of ObjectItems. An HCL file itself is an // ObjectList. type ObjectList struct { Items []*ObjectItem } func (o *ObjectList) Add(item *ObjectItem) { o.Items = append(o.Items, item) } // Filter filters out the objects with the given key list as a prefix. // // The returned list of objects contain ObjectItems where the keys have // this prefix already stripped off. This might result in objects with // zero-length key lists if they have no children. // // If no matches are found, an empty ObjectList (non-nil) is returned. func (o *ObjectList) Filter(keys ...string) *ObjectList { var result ObjectList for _, item := range o.Items { // If there aren't enough keys, then ignore this if len(item.Keys) < len(keys) { continue } match := true for i, key := range item.Keys[:len(keys)] { key := key.Token.Value().(string) if key != keys[i] && !strings.EqualFold(key, keys[i]) { match = false break } } if !match { continue } // Strip off the prefix from the children newItem := *item newItem.Keys = newItem.Keys[len(keys):] result.Add(&newItem) } return &result } // Children returns further nested objects (key length > 0) within this // ObjectList. This should be used with Filter to get at child items. func (o *ObjectList) Children() *ObjectList { var result ObjectList for _, item := range o.Items { if len(item.Keys) > 0 { result.Add(item) } } return &result } // Elem returns items in the list that are direct element assignments // (key length == 0). This should be used with Filter to get at elements. func (o *ObjectList) Elem() *ObjectList { var result ObjectList for _, item := range o.Items { if len(item.Keys) == 0 { result.Add(item) } } return &result } func (o *ObjectList) Pos() token.Pos { // If an Object has no members, it won't have a first item // to use as position if len(o.Items) == 0 { return unknownPos } // Return the uninitialized position return o.Items[0].Pos() } // ObjectItem represents a HCL Object Item. An item is represented with a key // (or keys). It can be an assignment or an object (both normal and nested) type ObjectItem struct { // keys is only one length long if it's of type assignment. If it's a // nested object it can be larger than one. In that case "assign" is // invalid as there is no assignments for a nested object. Keys []*ObjectKey // assign contains the position of "=", if any Assign token.Pos // val is the item itself. It can be an object,list, number, bool or a // string. If key length is larger than one, val can be only of type // Object. Val Node LeadComment *CommentGroup // associated lead comment LineComment *CommentGroup // associated line comment } func (o *ObjectItem) Pos() token.Pos { // If a parsed object has no keys, there is no position // for its first element. if len(o.Keys) == 0 { return unknownPos } return o.Keys[0].Pos() } // ObjectKeys are either an identifier or of type string. type ObjectKey struct { Token token.Token } func (o *ObjectKey) Pos() token.Pos { return o.Token.Pos } // LiteralType represents a literal of basic type. Valid types are: // token.NUMBER, token.FLOAT, token.BOOL and token.STRING type LiteralType struct { Token token.Token // comment types, only used when in a list LeadComment *CommentGroup LineComment *CommentGroup } func (l *LiteralType) Pos() token.Pos { return l.Token.Pos } // ListStatement represents a HCL List type type ListType struct { Lbrack token.Pos // position of "[" Rbrack token.Pos // position of "]" List []Node // the elements in lexical order } func (l *ListType) Pos() token.Pos { return l.Lbrack } func (l *ListType) Add(node Node) { l.List = append(l.List, node) } // ObjectType represents a HCL Object Type type ObjectType struct { Lbrace token.Pos // position of "{" Rbrace token.Pos // position of "}" List *ObjectList // the nodes in lexical order } func (o *ObjectType) Pos() token.Pos { return o.Lbrace } // Comment node represents a single //, # style or /*- style commment type Comment struct { Start token.Pos // position of / or # Text string } func (c *Comment) Pos() token.Pos { return c.Start } // CommentGroup node represents a sequence of comments with no other tokens and // no empty lines between. type CommentGroup struct { List []*Comment // len(List) > 0 } func (c *CommentGroup) Pos() token.Pos { return c.List[0].Pos() } //------------------------------------------------------------------- // GoStringer //------------------------------------------------------------------- func (o *ObjectKey) GoString() string { return fmt.Sprintf("*%#v", *o) } func (o *ObjectList) GoString() string { return fmt.Sprintf("*%#v", *o) } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/hcl/ast/walk.go ================================================ package ast import "fmt" // WalkFunc describes a function to be called for each node during a Walk. The // returned node can be used to rewrite the AST. Walking stops the returned // bool is false. type WalkFunc func(Node) (Node, bool) // Walk traverses an AST in depth-first order: It starts by calling fn(node); // node must not be nil. If fn returns true, Walk invokes fn recursively for // each of the non-nil children of node, followed by a call of fn(nil). The // returned node of fn can be used to rewrite the passed node to fn. func Walk(node Node, fn WalkFunc) Node { rewritten, ok := fn(node) if !ok { return rewritten } switch n := node.(type) { case *File: n.Node = Walk(n.Node, fn) case *ObjectList: for i, item := range n.Items { n.Items[i] = Walk(item, fn).(*ObjectItem) } case *ObjectKey: // nothing to do case *ObjectItem: for i, k := range n.Keys { n.Keys[i] = Walk(k, fn).(*ObjectKey) } if n.Val != nil { n.Val = Walk(n.Val, fn) } case *LiteralType: // nothing to do case *ListType: for i, l := range n.List { n.List[i] = Walk(l, fn) } case *ObjectType: n.List = Walk(n.List, fn).(*ObjectList) default: // should we panic here? fmt.Printf("unknown type: %T\n", n) } fn(nil) return rewritten } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/hcl/parser/error.go ================================================ package parser import ( "fmt" "github.com/hashicorp/hcl/hcl/token" ) // PosError is a parse error that contains a position. type PosError struct { Pos token.Pos Err error } func (e *PosError) Error() string { return fmt.Sprintf("At %s: %s", e.Pos, e.Err) } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/hcl/parser/parser.go ================================================ // Package parser implements a parser for HCL (HashiCorp Configuration // Language) package parser import ( "bytes" "errors" "fmt" "strings" "github.com/hashicorp/hcl/hcl/ast" "github.com/hashicorp/hcl/hcl/scanner" "github.com/hashicorp/hcl/hcl/token" ) type Parser struct { sc *scanner.Scanner // Last read token tok token.Token commaPrev token.Token comments []*ast.CommentGroup leadComment *ast.CommentGroup // last lead comment lineComment *ast.CommentGroup // last line comment enableTrace bool indent int n int // buffer size (max = 1) errorOnDuplicateKeys bool } func newParser(src []byte, errorOnDuplicateKeys bool) *Parser { return &Parser{ sc: scanner.New(src), errorOnDuplicateKeys: errorOnDuplicateKeys, } } // Parse returns the fully parsed source and returns the abstract syntax tree. func Parse(src []byte) (*ast.File, error) { return parse(src, true) } // Parse returns the fully parsed source and returns the abstract syntax tree. func ParseDontErrorOnDuplicateKeys(src []byte) (*ast.File, error) { return parse(src, false) } // Parse returns the fully parsed source and returns the abstract syntax tree. func parse(src []byte, errorOnDuplicateKeys bool) (*ast.File, error) { // normalize all line endings // since the scanner and output only work with "\n" line endings, we may // end up with dangling "\r" characters in the parsed data. src = bytes.Replace(src, []byte("\r\n"), []byte("\n"), -1) p := newParser(src, errorOnDuplicateKeys) return p.Parse() } var errEofToken = errors.New("EOF token found") // Parse returns the fully parsed source and returns the abstract syntax tree. func (p *Parser) Parse() (*ast.File, error) { f := &ast.File{} var err, scerr error p.sc.Error = func(pos token.Pos, msg string) { scerr = &PosError{Pos: pos, Err: errors.New(msg)} } f.Node, err = p.objectList(false) if scerr != nil { return nil, scerr } if err != nil { return nil, err } f.Comments = p.comments return f, nil } // objectList parses a list of items within an object (generally k/v pairs). // The parameter" obj" tells this whether to we are within an object (braces: // '{', '}') or just at the top level. If we're within an object, we end // at an RBRACE. func (p *Parser) objectList(obj bool) (*ast.ObjectList, error) { defer un(trace(p, "ParseObjectList")) node := &ast.ObjectList{} seenKeys := map[string]struct{}{} for { if obj { tok := p.scan() p.unscan() if tok.Type == token.RBRACE { break } } n, err := p.objectItem() if err == errEofToken { break // we are finished } else if err != nil { return nil, err } if n.Assign.String() != "-" { for _, key := range n.Keys { if !p.errorOnDuplicateKeys { break } _, ok := seenKeys[key.Token.Text] if ok { return nil, errors.New(fmt.Sprintf("The argument %q at %s was already set. Each argument can only be defined once", key.Token.Text, key.Token.Pos.String())) } seenKeys[key.Token.Text] = struct{}{} } } // we don't return a nil node, because might want to use already // collected items. if err != nil { return node, err } node.Add(n) // object lists can be optionally comma-delimited e.g. when a list of maps // is being expressed, so a comma is allowed here - it's simply consumed tok := p.scan() if tok.Type != token.COMMA { p.unscan() } } return node, nil } func (p *Parser) consumeComment() (comment *ast.Comment, endline int) { endline = p.tok.Pos.Line // count the endline if it's multiline comment, ie starting with /* if len(p.tok.Text) > 1 && p.tok.Text[1] == '*' { // don't use range here - no need to decode Unicode code points for i := 0; i < len(p.tok.Text); i++ { if p.tok.Text[i] == '\n' { endline++ } } } comment = &ast.Comment{Start: p.tok.Pos, Text: p.tok.Text} p.tok = p.sc.Scan() return } func (p *Parser) consumeCommentGroup(n int) (comments *ast.CommentGroup, endline int) { var list []*ast.Comment endline = p.tok.Pos.Line for p.tok.Type == token.COMMENT && p.tok.Pos.Line <= endline+n { var comment *ast.Comment comment, endline = p.consumeComment() list = append(list, comment) } // add comment group to the comments list comments = &ast.CommentGroup{List: list} p.comments = append(p.comments, comments) return } // objectItem parses a single object item func (p *Parser) objectItem() (*ast.ObjectItem, error) { defer un(trace(p, "ParseObjectItem")) keys, err := p.objectKey() if len(keys) > 0 && err == errEofToken { // We ignore eof token here since it is an error if we didn't // receive a value (but we did receive a key) for the item. err = nil } if len(keys) > 0 && err != nil && p.tok.Type == token.RBRACE { // This is a strange boolean statement, but what it means is: // We have keys with no value, and we're likely in an object // (since RBrace ends an object). For this, we set err to nil so // we continue and get the error below of having the wrong value // type. err = nil // Reset the token type so we don't think it completed fine. See // objectType which uses p.tok.Type to check if we're done with // the object. p.tok.Type = token.EOF } if err != nil { return nil, err } o := &ast.ObjectItem{ Keys: keys, } if p.leadComment != nil { o.LeadComment = p.leadComment p.leadComment = nil } switch p.tok.Type { case token.ASSIGN: o.Assign = p.tok.Pos o.Val, err = p.object() if err != nil { return nil, err } case token.LBRACE: o.Val, err = p.objectType() if err != nil { return nil, err } default: keyStr := make([]string, 0, len(keys)) for _, k := range keys { keyStr = append(keyStr, k.Token.Text) } return nil, &PosError{ Pos: p.tok.Pos, Err: fmt.Errorf( "key '%s' expected start of object ('{') or assignment ('=')", strings.Join(keyStr, " ")), } } // key=#comment // val if p.lineComment != nil { o.LineComment, p.lineComment = p.lineComment, nil } // do a look-ahead for line comment p.scan() if len(keys) > 0 && o.Val.Pos().Line == keys[0].Pos().Line && p.lineComment != nil { o.LineComment = p.lineComment p.lineComment = nil } p.unscan() return o, nil } // objectKey parses an object key and returns a ObjectKey AST func (p *Parser) objectKey() ([]*ast.ObjectKey, error) { keyCount := 0 keys := make([]*ast.ObjectKey, 0) for { tok := p.scan() switch tok.Type { case token.EOF: // It is very important to also return the keys here as well as // the error. This is because we need to be able to tell if we // did parse keys prior to finding the EOF, or if we just found // a bare EOF. return keys, errEofToken case token.ASSIGN: // assignment or object only, but not nested objects. this is not // allowed: `foo bar = {}` if keyCount > 1 { return nil, &PosError{ Pos: p.tok.Pos, Err: fmt.Errorf("nested object expected: LBRACE got: %s", p.tok.Type), } } if keyCount == 0 { return nil, &PosError{ Pos: p.tok.Pos, Err: errors.New("no object keys found!"), } } return keys, nil case token.LBRACE: var err error // If we have no keys, then it is a syntax error. i.e. {{}} is not // allowed. if len(keys) == 0 { err = &PosError{ Pos: p.tok.Pos, Err: fmt.Errorf("expected: IDENT | STRING got: %s", p.tok.Type), } } // object return keys, err case token.IDENT, token.STRING: keyCount++ keys = append(keys, &ast.ObjectKey{Token: p.tok}) case token.ILLEGAL: return keys, &PosError{ Pos: p.tok.Pos, Err: fmt.Errorf("illegal character"), } default: return keys, &PosError{ Pos: p.tok.Pos, Err: fmt.Errorf("expected: IDENT | STRING | ASSIGN | LBRACE got: %s", p.tok.Type), } } } } // object parses any type of object, such as number, bool, string, object or // list. func (p *Parser) object() (ast.Node, error) { defer un(trace(p, "ParseType")) tok := p.scan() switch tok.Type { case token.NUMBER, token.FLOAT, token.BOOL, token.STRING, token.HEREDOC: return p.literalType() case token.LBRACE: return p.objectType() case token.LBRACK: return p.listType() case token.COMMENT: // implement comment case token.EOF: return nil, errEofToken } return nil, &PosError{ Pos: tok.Pos, Err: fmt.Errorf("Unknown token: %+v", tok), } } // objectType parses an object type and returns a ObjectType AST func (p *Parser) objectType() (*ast.ObjectType, error) { defer un(trace(p, "ParseObjectType")) // we assume that the currently scanned token is a LBRACE o := &ast.ObjectType{ Lbrace: p.tok.Pos, } l, err := p.objectList(true) // if we hit RBRACE, we are good to go (means we parsed all Items), if it's // not a RBRACE, it's an syntax error and we just return it. if err != nil && p.tok.Type != token.RBRACE { return nil, err } else if err != nil { return nil, err } // No error, scan and expect the ending to be a brace if tok := p.scan(); tok.Type != token.RBRACE { return nil, &PosError{ Pos: tok.Pos, Err: fmt.Errorf("object expected closing RBRACE got: %s", tok.Type), } } o.List = l o.Rbrace = p.tok.Pos // advanced via parseObjectList return o, nil } // listType parses a list type and returns a ListType AST func (p *Parser) listType() (*ast.ListType, error) { defer un(trace(p, "ParseListType")) // we assume that the currently scanned token is a LBRACK l := &ast.ListType{ Lbrack: p.tok.Pos, } needComma := false for { tok := p.scan() if needComma { switch tok.Type { case token.COMMA, token.RBRACK: default: return nil, &PosError{ Pos: tok.Pos, Err: fmt.Errorf( "error parsing list, expected comma or list end, got: %s", tok.Type), } } } switch tok.Type { case token.BOOL, token.NUMBER, token.FLOAT, token.STRING, token.HEREDOC: node, err := p.literalType() if err != nil { return nil, err } // If there is a lead comment, apply it if p.leadComment != nil { node.LeadComment = p.leadComment p.leadComment = nil } l.Add(node) needComma = true case token.COMMA: // get next list item or we are at the end // do a look-ahead for line comment p.scan() if p.lineComment != nil && len(l.List) > 0 { lit, ok := l.List[len(l.List)-1].(*ast.LiteralType) if ok { lit.LineComment = p.lineComment l.List[len(l.List)-1] = lit p.lineComment = nil } } p.unscan() needComma = false continue case token.LBRACE: // Looks like a nested object, so parse it out node, err := p.objectType() if err != nil { return nil, &PosError{ Pos: tok.Pos, Err: fmt.Errorf( "error while trying to parse object within list: %s", err), } } l.Add(node) needComma = true case token.LBRACK: node, err := p.listType() if err != nil { return nil, &PosError{ Pos: tok.Pos, Err: fmt.Errorf( "error while trying to parse list within list: %s", err), } } l.Add(node) case token.RBRACK: // finished l.Rbrack = p.tok.Pos return l, nil default: return nil, &PosError{ Pos: tok.Pos, Err: fmt.Errorf("unexpected token while parsing list: %s", tok.Type), } } } } // literalType parses a literal type and returns a LiteralType AST func (p *Parser) literalType() (*ast.LiteralType, error) { defer un(trace(p, "ParseLiteral")) return &ast.LiteralType{ Token: p.tok, }, nil } // scan returns the next token from the underlying scanner. If a token has // been unscanned then read that instead. In the process, it collects any // comment groups encountered, and remembers the last lead and line comments. func (p *Parser) scan() token.Token { // If we have a token on the buffer, then return it. if p.n != 0 { p.n = 0 return p.tok } // Otherwise read the next token from the scanner and Save it to the buffer // in case we unscan later. prev := p.tok p.tok = p.sc.Scan() if p.tok.Type == token.COMMENT { var comment *ast.CommentGroup var endline int // fmt.Printf("p.tok.Pos.Line = %+v prev: %d endline %d \n", // p.tok.Pos.Line, prev.Pos.Line, endline) if p.tok.Pos.Line == prev.Pos.Line { // The comment is on same line as the previous token; it // cannot be a lead comment but may be a line comment. comment, endline = p.consumeCommentGroup(0) if p.tok.Pos.Line != endline { // The next token is on a different line, thus // the last comment group is a line comment. p.lineComment = comment } } // consume successor comments, if any endline = -1 for p.tok.Type == token.COMMENT { comment, endline = p.consumeCommentGroup(1) } if endline+1 == p.tok.Pos.Line && p.tok.Type != token.RBRACE { switch p.tok.Type { case token.RBRACE, token.RBRACK: // Do not count for these cases default: // The next token is following on the line immediately after the // comment group, thus the last comment group is a lead comment. p.leadComment = comment } } } return p.tok } // unscan pushes the previously read token back onto the buffer. func (p *Parser) unscan() { p.n = 1 } // ---------------------------------------------------------------------------- // Parsing support func (p *Parser) printTrace(a ...interface{}) { if !p.enableTrace { return } const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " const n = len(dots) fmt.Printf("%5d:%3d: ", p.tok.Pos.Line, p.tok.Pos.Column) i := 2 * p.indent for i > n { fmt.Print(dots) i -= n } // i <= n fmt.Print(dots[0:i]) fmt.Println(a...) } func trace(p *Parser, msg string) *Parser { p.printTrace(msg, "(") p.indent++ return p } // Usage pattern: defer un(trace(p, "...")) func un(p *Parser) { p.indent-- p.printTrace(")") } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/hcl/scanner/scanner.go ================================================ // Package scanner implements a scanner for HCL (HashiCorp Configuration // Language) source text. package scanner import ( "bytes" "fmt" "os" "regexp" "unicode" "unicode/utf8" "github.com/hashicorp/hcl/hcl/token" ) // eof represents a marker rune for the end of the reader. const eof = rune(0) // Scanner defines a lexical scanner type Scanner struct { buf *bytes.Buffer // Source buffer for advancing and scanning src []byte // Source buffer for immutable access // Source Position srcPos token.Pos // current position prevPos token.Pos // previous position, used for peek() method lastCharLen int // length of last character in bytes lastLineLen int // length of last line in characters (for correct column reporting) tokStart int // token text start position tokEnd int // token text end position // Error is called for each error encountered. If no Error // function is set, the error is reported to os.Stderr. Error func(pos token.Pos, msg string) // ErrorCount is incremented by one for each error encountered. ErrorCount int // tokPos is the start position of most recently scanned token; set by // Scan. The Filename field is always left untouched by the Scanner. If // an error is reported (via Error) and Position is invalid, the scanner is // not inside a token. tokPos token.Pos } // New creates and initializes a new instance of Scanner using src as // its source content. func New(src []byte) *Scanner { // even though we accept a src, we read from a io.Reader compatible type // (*bytes.Buffer). So in the future we might easily change it to streaming // read. b := bytes.NewBuffer(src) s := &Scanner{ buf: b, src: src, } // srcPosition always starts with 1 s.srcPos.Line = 1 return s } // next reads the next rune from the bufferred reader. Returns the rune(0) if // an error occurs (or io.EOF is returned). func (s *Scanner) next() rune { ch, size, err := s.buf.ReadRune() if err != nil { // advance for error reporting s.srcPos.Column++ s.srcPos.Offset += size s.lastCharLen = size return eof } // remember last position s.prevPos = s.srcPos s.srcPos.Column++ s.lastCharLen = size s.srcPos.Offset += size if ch == utf8.RuneError && size == 1 { s.err("illegal UTF-8 encoding") return ch } if ch == '\n' { s.srcPos.Line++ s.lastLineLen = s.srcPos.Column s.srcPos.Column = 0 } if ch == '\x00' { s.err("unexpected null character (0x00)") return eof } if ch == '\uE123' { s.err("unicode code point U+E123 reserved for internal use") return utf8.RuneError } // debug // fmt.Printf("ch: %q, offset:column: %d:%d\n", ch, s.srcPos.Offset, s.srcPos.Column) return ch } // unread unreads the previous read Rune and updates the source position func (s *Scanner) unread() { if err := s.buf.UnreadRune(); err != nil { panic(err) // this is user fault, we should catch it } s.srcPos = s.prevPos // put back last position } // peek returns the next rune without advancing the reader. func (s *Scanner) peek() rune { peek, _, err := s.buf.ReadRune() if err != nil { return eof } s.buf.UnreadRune() return peek } // Scan scans the next token and returns the token. func (s *Scanner) Scan() token.Token { ch := s.next() // skip white space for isWhitespace(ch) { ch = s.next() } var tok token.Type // token text markings s.tokStart = s.srcPos.Offset - s.lastCharLen // token position, initial next() is moving the offset by one(size of rune // actually), though we are interested with the starting point s.tokPos.Offset = s.srcPos.Offset - s.lastCharLen if s.srcPos.Column > 0 { // common case: last character was not a '\n' s.tokPos.Line = s.srcPos.Line s.tokPos.Column = s.srcPos.Column } else { // last character was a '\n' // (we cannot be at the beginning of the source // since we have called next() at least once) s.tokPos.Line = s.srcPos.Line - 1 s.tokPos.Column = s.lastLineLen } switch { case isLetter(ch): tok = token.IDENT lit := s.scanIdentifier() if lit == "true" || lit == "false" { tok = token.BOOL } case isDecimal(ch): tok = s.scanNumber(ch) default: switch ch { case eof: tok = token.EOF case '"': tok = token.STRING s.scanString() case '#', '/': tok = token.COMMENT s.scanComment(ch) case '.': tok = token.PERIOD ch = s.peek() if isDecimal(ch) { tok = token.FLOAT ch = s.scanMantissa(ch) ch = s.scanExponent(ch) } case '<': tok = token.HEREDOC s.scanHeredoc() case '[': tok = token.LBRACK case ']': tok = token.RBRACK case '{': tok = token.LBRACE case '}': tok = token.RBRACE case ',': tok = token.COMMA case '=': tok = token.ASSIGN case '+': tok = token.ADD case '-': if isDecimal(s.peek()) { ch := s.next() tok = s.scanNumber(ch) } else { tok = token.SUB } default: s.err("illegal char") } } // finish token ending s.tokEnd = s.srcPos.Offset // create token literal var tokenText string if s.tokStart >= 0 { tokenText = string(s.src[s.tokStart:s.tokEnd]) } s.tokStart = s.tokEnd // ensure idempotency of tokenText() call return token.Token{ Type: tok, Pos: s.tokPos, Text: tokenText, } } func (s *Scanner) scanComment(ch rune) { // single line comments if ch == '#' || (ch == '/' && s.peek() != '*') { if ch == '/' && s.peek() != '/' { s.err("expected '/' for comment") return } ch = s.next() for ch != '\n' && ch >= 0 && ch != eof { ch = s.next() } if ch != eof && ch >= 0 { s.unread() } return } // be sure we get the character after /* This allows us to find comment's // that are not erminated if ch == '/' { s.next() ch = s.next() // read character after "/*" } // look for /* - style comments for { if ch < 0 || ch == eof { s.err("comment not terminated") break } ch0 := ch ch = s.next() if ch0 == '*' && ch == '/' { break } } } // scanNumber scans a HCL number definition starting with the given rune func (s *Scanner) scanNumber(ch rune) token.Type { if ch == '0' { // check for hexadecimal, octal or float ch = s.next() if ch == 'x' || ch == 'X' { // hexadecimal ch = s.next() found := false for isHexadecimal(ch) { ch = s.next() found = true } if !found { s.err("illegal hexadecimal number") } if ch != eof { s.unread() } return token.NUMBER } // now it's either something like: 0421(octal) or 0.1231(float) illegalOctal := false for isDecimal(ch) { ch = s.next() if ch == '8' || ch == '9' { // this is just a possibility. For example 0159 is illegal, but // 0159.23 is valid. So we mark a possible illegal octal. If // the next character is not a period, we'll print the error. illegalOctal = true } } if ch == 'e' || ch == 'E' { ch = s.scanExponent(ch) return token.FLOAT } if ch == '.' { ch = s.scanFraction(ch) if ch == 'e' || ch == 'E' { ch = s.next() ch = s.scanExponent(ch) } return token.FLOAT } if illegalOctal { s.err("illegal octal number") } if ch != eof { s.unread() } return token.NUMBER } s.scanMantissa(ch) ch = s.next() // seek forward if ch == 'e' || ch == 'E' { ch = s.scanExponent(ch) return token.FLOAT } if ch == '.' { ch = s.scanFraction(ch) if ch == 'e' || ch == 'E' { ch = s.next() ch = s.scanExponent(ch) } return token.FLOAT } if ch != eof { s.unread() } return token.NUMBER } // scanMantissa scans the mantissa beginning from the rune. It returns the next // non decimal rune. It's used to determine wheter it's a fraction or exponent. func (s *Scanner) scanMantissa(ch rune) rune { scanned := false for isDecimal(ch) { ch = s.next() scanned = true } if scanned && ch != eof { s.unread() } return ch } // scanFraction scans the fraction after the '.' rune func (s *Scanner) scanFraction(ch rune) rune { if ch == '.' { ch = s.peek() // we peek just to see if we can move forward ch = s.scanMantissa(ch) } return ch } // scanExponent scans the remaining parts of an exponent after the 'e' or 'E' // rune. func (s *Scanner) scanExponent(ch rune) rune { if ch == 'e' || ch == 'E' { ch = s.next() if ch == '-' || ch == '+' { ch = s.next() } ch = s.scanMantissa(ch) } return ch } // scanHeredoc scans a heredoc string func (s *Scanner) scanHeredoc() { // Scan the second '<' in example: '<= len(identBytes) && identRegexp.Match(s.src[lineStart:s.srcPos.Offset-s.lastCharLen]) { break } // Not an anchor match, record the start of a new line lineStart = s.srcPos.Offset } if ch == eof { s.err("heredoc not terminated") return } } return } // scanString scans a quoted string func (s *Scanner) scanString() { braces := 0 for { // '"' opening already consumed // read character after quote ch := s.next() if (ch == '\n' && braces == 0) || ch < 0 || ch == eof { s.err("literal not terminated") return } if ch == '"' && braces == 0 { break } // If we're going into a ${} then we can ignore quotes for awhile if braces == 0 && ch == '$' && s.peek() == '{' { braces++ s.next() } else if braces > 0 && ch == '{' { braces++ } if braces > 0 && ch == '}' { braces-- } if ch == '\\' { s.scanEscape() } } return } // scanEscape scans an escape sequence func (s *Scanner) scanEscape() rune { // http://en.cppreference.com/w/cpp/language/escape ch := s.next() // read character after '/' switch ch { case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"': // nothing to do case '0', '1', '2', '3', '4', '5', '6', '7': // octal notation ch = s.scanDigits(ch, 8, 3) case 'x': // hexademical notation ch = s.scanDigits(s.next(), 16, 2) case 'u': // universal character name ch = s.scanDigits(s.next(), 16, 4) case 'U': // universal character name ch = s.scanDigits(s.next(), 16, 8) default: s.err("illegal char escape") } return ch } // scanDigits scans a rune with the given base for n times. For example an // octal notation \184 would yield in scanDigits(ch, 8, 3) func (s *Scanner) scanDigits(ch rune, base, n int) rune { start := n for n > 0 && digitVal(ch) < base { ch = s.next() if ch == eof { // If we see an EOF, we halt any more scanning of digits // immediately. break } n-- } if n > 0 { s.err("illegal char escape") } if n != start && ch != eof { // we scanned all digits, put the last non digit char back, // only if we read anything at all s.unread() } return ch } // scanIdentifier scans an identifier and returns the literal string func (s *Scanner) scanIdentifier() string { offs := s.srcPos.Offset - s.lastCharLen ch := s.next() for isLetter(ch) || isDigit(ch) || ch == '-' || ch == '.' { ch = s.next() } if ch != eof { s.unread() // we got identifier, put back latest char } return string(s.src[offs:s.srcPos.Offset]) } // recentPosition returns the position of the character immediately after the // character or token returned by the last call to Scan. func (s *Scanner) recentPosition() (pos token.Pos) { pos.Offset = s.srcPos.Offset - s.lastCharLen switch { case s.srcPos.Column > 0: // common case: last character was not a '\n' pos.Line = s.srcPos.Line pos.Column = s.srcPos.Column case s.lastLineLen > 0: // last character was a '\n' // (we cannot be at the beginning of the source // since we have called next() at least once) pos.Line = s.srcPos.Line - 1 pos.Column = s.lastLineLen default: // at the beginning of the source pos.Line = 1 pos.Column = 1 } return } // err prints the error of any scanning to s.Error function. If the function is // not defined, by default it prints them to os.Stderr func (s *Scanner) err(msg string) { s.ErrorCount++ pos := s.recentPosition() if s.Error != nil { s.Error(pos, msg) return } fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg) } // isHexadecimal returns true if the given rune is a letter func isLetter(ch rune) bool { return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch) } // isDigit returns true if the given rune is a decimal digit func isDigit(ch rune) bool { return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch) } // isDecimal returns true if the given rune is a decimal number func isDecimal(ch rune) bool { return '0' <= ch && ch <= '9' } // isHexadecimal returns true if the given rune is an hexadecimal number func isHexadecimal(ch rune) bool { return '0' <= ch && ch <= '9' || 'a' <= ch && ch <= 'f' || 'A' <= ch && ch <= 'F' } // isWhitespace returns true if the rune is a space, tab, newline or carriage return func isWhitespace(ch rune) bool { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' } // digitVal returns the integer value of a given octal,decimal or hexadecimal rune func digitVal(ch rune) int { switch { case '0' <= ch && ch <= '9': return int(ch - '0') case 'a' <= ch && ch <= 'f': return int(ch - 'a' + 10) case 'A' <= ch && ch <= 'F': return int(ch - 'A' + 10) } return 16 // larger than any legal digit val } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/hcl/strconv/quote.go ================================================ package strconv import ( "errors" "unicode/utf8" ) // ErrSyntax indicates that a value does not have the right syntax for the target type. var ErrSyntax = errors.New("invalid syntax") // Unquote interprets s as a single-quoted, double-quoted, // or backquoted Go string literal, returning the string value // that s quotes. (If s is single-quoted, it would be a Go // character literal; Unquote returns the corresponding // one-character string.) func Unquote(s string) (t string, err error) { n := len(s) if n < 2 { return "", ErrSyntax } quote := s[0] if quote != s[n-1] { return "", ErrSyntax } s = s[1 : n-1] if quote != '"' { return "", ErrSyntax } if !contains(s, '$') && !contains(s, '{') && contains(s, '\n') { return "", ErrSyntax } // Is it trivial? Avoid allocation. if !contains(s, '\\') && !contains(s, quote) && !contains(s, '$') { switch quote { case '"': return s, nil case '\'': r, size := utf8.DecodeRuneInString(s) if size == len(s) && (r != utf8.RuneError || size != 1) { return s, nil } } } var runeTmp [utf8.UTFMax]byte buf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations. for len(s) > 0 { // If we're starting a '${}' then let it through un-unquoted. // Specifically: we don't unquote any characters within the `${}` // section. if s[0] == '$' && len(s) > 1 && s[1] == '{' { buf = append(buf, '$', '{') s = s[2:] // Continue reading until we find the closing brace, copying as-is braces := 1 for len(s) > 0 && braces > 0 { r, size := utf8.DecodeRuneInString(s) if r == utf8.RuneError { return "", ErrSyntax } s = s[size:] n := utf8.EncodeRune(runeTmp[:], r) buf = append(buf, runeTmp[:n]...) switch r { case '{': braces++ case '}': braces-- } } if braces != 0 { return "", ErrSyntax } if len(s) == 0 { // If there's no string left, we're done! break } else { // If there's more left, we need to pop back up to the top of the loop // in case there's another interpolation in this string. continue } } if s[0] == '\n' { return "", ErrSyntax } c, multibyte, ss, err := unquoteChar(s, quote) if err != nil { return "", err } s = ss if c < utf8.RuneSelf || !multibyte { buf = append(buf, byte(c)) } else { n := utf8.EncodeRune(runeTmp[:], c) buf = append(buf, runeTmp[:n]...) } if quote == '\'' && len(s) != 0 { // single-quoted must be single character return "", ErrSyntax } } return string(buf), nil } // contains reports whether the string contains the byte c. func contains(s string, c byte) bool { for i := 0; i < len(s); i++ { if s[i] == c { return true } } return false } func unhex(b byte) (v rune, ok bool) { c := rune(b) switch { case '0' <= c && c <= '9': return c - '0', true case 'a' <= c && c <= 'f': return c - 'a' + 10, true case 'A' <= c && c <= 'F': return c - 'A' + 10, true } return } func unquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, err error) { // easy cases switch c := s[0]; { case c == quote && (quote == '\'' || quote == '"'): err = ErrSyntax return case c >= utf8.RuneSelf: r, size := utf8.DecodeRuneInString(s) return r, true, s[size:], nil case c != '\\': return rune(s[0]), false, s[1:], nil } // hard case: c is backslash if len(s) <= 1 { err = ErrSyntax return } c := s[1] s = s[2:] switch c { case 'a': value = '\a' case 'b': value = '\b' case 'f': value = '\f' case 'n': value = '\n' case 'r': value = '\r' case 't': value = '\t' case 'v': value = '\v' case 'x', 'u', 'U': n := 0 switch c { case 'x': n = 2 case 'u': n = 4 case 'U': n = 8 } var v rune if len(s) < n { err = ErrSyntax return } for j := 0; j < n; j++ { x, ok := unhex(s[j]) if !ok { err = ErrSyntax return } v = v<<4 | x } s = s[n:] if c == 'x' { // single-byte string, possibly not UTF-8 value = v break } if v > utf8.MaxRune { err = ErrSyntax return } value = v multibyte = true case '0', '1', '2', '3', '4', '5', '6', '7': v := rune(c) - '0' if len(s) < 2 { err = ErrSyntax return } for j := 0; j < 2; j++ { // one digit already; two more x := rune(s[j]) - '0' if x < 0 || x > 7 { err = ErrSyntax return } v = (v << 3) | x } s = s[2:] if v > 255 { err = ErrSyntax return } value = v case '\\': value = '\\' case '\'', '"': if c != quote { err = ErrSyntax return } value = rune(c) default: err = ErrSyntax return } tail = s return } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/hcl/token/position.go ================================================ package token import "fmt" // Pos describes an arbitrary source position // including the file, line, and column location. // A Position is valid if the line number is > 0. type Pos struct { Filename string // filename, if any Offset int // offset, starting at 0 Line int // line number, starting at 1 Column int // column number, starting at 1 (character count) } // IsValid returns true if the position is valid. func (p *Pos) IsValid() bool { return p.Line > 0 } // String returns a string in one of several forms: // // file:line:column valid position with file name // line:column valid position without file name // file invalid position with file name // - invalid position without file name func (p Pos) String() string { s := p.Filename if p.IsValid() { if s != "" { s += ":" } s += fmt.Sprintf("%d:%d", p.Line, p.Column) } if s == "" { s = "-" } return s } // Before reports whether the position p is before u. func (p Pos) Before(u Pos) bool { return u.Offset > p.Offset || u.Line > p.Line } // After reports whether the position p is after u. func (p Pos) After(u Pos) bool { return u.Offset < p.Offset || u.Line < p.Line } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/hcl/token/token.go ================================================ // Package token defines constants representing the lexical tokens for HCL // (HashiCorp Configuration Language) package token import ( "fmt" "strconv" "strings" hclstrconv "github.com/hashicorp/hcl/hcl/strconv" ) // Token defines a single HCL token which can be obtained via the Scanner type Token struct { Type Type Pos Pos Text string JSON bool } // Type is the set of lexical tokens of the HCL (HashiCorp Configuration Language) type Type int const ( // Special tokens ILLEGAL Type = iota EOF COMMENT identifier_beg IDENT // literals literal_beg NUMBER // 12345 FLOAT // 123.45 BOOL // true,false STRING // "abc" HEREDOC // < 0 { // Pop the current item n := len(frontier) item := frontier[n-1] frontier = frontier[:n-1] switch v := item.Val.(type) { case *ast.ObjectType: items, frontier = flattenObjectType(v, item, items, frontier) case *ast.ListType: items, frontier = flattenListType(v, item, items, frontier) default: items = append(items, item) } } // Reverse the list since the frontier model runs things backwards for i := len(items)/2 - 1; i >= 0; i-- { opp := len(items) - 1 - i items[i], items[opp] = items[opp], items[i] } // Done! Set the original items list.Items = items return n, true }) } func flattenListType( ot *ast.ListType, item *ast.ObjectItem, items []*ast.ObjectItem, frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) { // If the list is empty, keep the original list if len(ot.List) == 0 { items = append(items, item) return items, frontier } // All the elements of this object must also be objects! for _, subitem := range ot.List { if _, ok := subitem.(*ast.ObjectType); !ok { items = append(items, item) return items, frontier } } // Great! We have a match go through all the items and flatten for _, elem := range ot.List { // Add it to the frontier so that we can recurse frontier = append(frontier, &ast.ObjectItem{ Keys: item.Keys, Assign: item.Assign, Val: elem, LeadComment: item.LeadComment, LineComment: item.LineComment, }) } return items, frontier } func flattenObjectType( ot *ast.ObjectType, item *ast.ObjectItem, items []*ast.ObjectItem, frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) { // If the list has no items we do not have to flatten anything if ot.List.Items == nil { items = append(items, item) return items, frontier } // All the elements of this object must also be objects! for _, subitem := range ot.List.Items { if _, ok := subitem.Val.(*ast.ObjectType); !ok { items = append(items, item) return items, frontier } } // Great! We have a match go through all the items and flatten for _, subitem := range ot.List.Items { // Copy the new key keys := make([]*ast.ObjectKey, len(item.Keys)+len(subitem.Keys)) copy(keys, item.Keys) copy(keys[len(item.Keys):], subitem.Keys) // Add it to the frontier so that we can recurse frontier = append(frontier, &ast.ObjectItem{ Keys: keys, Assign: item.Assign, Val: subitem.Val, LeadComment: item.LeadComment, LineComment: item.LineComment, }) } return items, frontier } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/json/parser/parser.go ================================================ package parser import ( "errors" "fmt" "github.com/hashicorp/hcl/hcl/ast" hcltoken "github.com/hashicorp/hcl/hcl/token" "github.com/hashicorp/hcl/json/scanner" "github.com/hashicorp/hcl/json/token" ) type Parser struct { sc *scanner.Scanner // Last read token tok token.Token commaPrev token.Token enableTrace bool indent int n int // buffer size (max = 1) } func newParser(src []byte) *Parser { return &Parser{ sc: scanner.New(src), } } // Parse returns the fully parsed source and returns the abstract syntax tree. func Parse(src []byte) (*ast.File, error) { p := newParser(src) return p.Parse() } var errEofToken = errors.New("EOF token found") // Parse returns the fully parsed source and returns the abstract syntax tree. func (p *Parser) Parse() (*ast.File, error) { f := &ast.File{} var err, scerr error p.sc.Error = func(pos token.Pos, msg string) { scerr = fmt.Errorf("%s: %s", pos, msg) } // The root must be an object in JSON object, err := p.object() if scerr != nil { return nil, scerr } if err != nil { return nil, err } // We make our final node an object list so it is more HCL compatible f.Node = object.List // Flatten it, which finds patterns and turns them into more HCL-like // AST trees. flattenObjects(f.Node) return f, nil } func (p *Parser) objectList() (*ast.ObjectList, error) { defer un(trace(p, "ParseObjectList")) node := &ast.ObjectList{} for { n, err := p.objectItem() if err == errEofToken { break // we are finished } // we don't return a nil node, because might want to use already // collected items. if err != nil { return node, err } node.Add(n) // Check for a followup comma. If it isn't a comma, then we're done if tok := p.scan(); tok.Type != token.COMMA { break } } return node, nil } // objectItem parses a single object item func (p *Parser) objectItem() (*ast.ObjectItem, error) { defer un(trace(p, "ParseObjectItem")) keys, err := p.objectKey() if err != nil { return nil, err } o := &ast.ObjectItem{ Keys: keys, } switch p.tok.Type { case token.COLON: pos := p.tok.Pos o.Assign = hcltoken.Pos{ Filename: pos.Filename, Offset: pos.Offset, Line: pos.Line, Column: pos.Column, } o.Val, err = p.objectValue() if err != nil { return nil, err } } return o, nil } // objectKey parses an object key and returns a ObjectKey AST func (p *Parser) objectKey() ([]*ast.ObjectKey, error) { keyCount := 0 keys := make([]*ast.ObjectKey, 0) for { tok := p.scan() switch tok.Type { case token.EOF: return nil, errEofToken case token.STRING: keyCount++ keys = append(keys, &ast.ObjectKey{ Token: p.tok.HCLToken(), }) case token.COLON: // If we have a zero keycount it means that we never got // an object key, i.e. `{ :`. This is a syntax error. if keyCount == 0 { return nil, fmt.Errorf("expected: STRING got: %s", p.tok.Type) } // Done return keys, nil case token.ILLEGAL: return nil, errors.New("illegal") default: return nil, fmt.Errorf("expected: STRING got: %s", p.tok.Type) } } } // object parses any type of object, such as number, bool, string, object or // list. func (p *Parser) objectValue() (ast.Node, error) { defer un(trace(p, "ParseObjectValue")) tok := p.scan() switch tok.Type { case token.NUMBER, token.FLOAT, token.BOOL, token.NULL, token.STRING: return p.literalType() case token.LBRACE: return p.objectType() case token.LBRACK: return p.listType() case token.EOF: return nil, errEofToken } return nil, fmt.Errorf("Expected object value, got unknown token: %+v", tok) } // object parses any type of object, such as number, bool, string, object or // list. func (p *Parser) object() (*ast.ObjectType, error) { defer un(trace(p, "ParseType")) tok := p.scan() switch tok.Type { case token.LBRACE: return p.objectType() case token.EOF: return nil, errEofToken } return nil, fmt.Errorf("Expected object, got unknown token: %+v", tok) } // objectType parses an object type and returns a ObjectType AST func (p *Parser) objectType() (*ast.ObjectType, error) { defer un(trace(p, "ParseObjectType")) // we assume that the currently scanned token is a LBRACE o := &ast.ObjectType{} l, err := p.objectList() // if we hit RBRACE, we are good to go (means we parsed all Items), if it's // not a RBRACE, it's an syntax error and we just return it. if err != nil && p.tok.Type != token.RBRACE { return nil, err } o.List = l return o, nil } // listType parses a list type and returns a ListType AST func (p *Parser) listType() (*ast.ListType, error) { defer un(trace(p, "ParseListType")) // we assume that the currently scanned token is a LBRACK l := &ast.ListType{} for { tok := p.scan() switch tok.Type { case token.NUMBER, token.FLOAT, token.STRING: node, err := p.literalType() if err != nil { return nil, err } l.Add(node) case token.COMMA: continue case token.LBRACE: node, err := p.objectType() if err != nil { return nil, err } l.Add(node) case token.BOOL: // TODO(arslan) should we support? not supported by HCL yet case token.LBRACK: // TODO(arslan) should we support nested lists? Even though it's // written in README of HCL, it's not a part of the grammar // (not defined in parse.y) case token.RBRACK: // finished return l, nil default: return nil, fmt.Errorf("unexpected token while parsing list: %s", tok.Type) } } } // literalType parses a literal type and returns a LiteralType AST func (p *Parser) literalType() (*ast.LiteralType, error) { defer un(trace(p, "ParseLiteral")) return &ast.LiteralType{ Token: p.tok.HCLToken(), }, nil } // scan returns the next token from the underlying scanner. If a token has // been unscanned then read that instead. func (p *Parser) scan() token.Token { // If we have a token on the buffer, then return it. if p.n != 0 { p.n = 0 return p.tok } p.tok = p.sc.Scan() return p.tok } // unscan pushes the previously read token back onto the buffer. func (p *Parser) unscan() { p.n = 1 } // ---------------------------------------------------------------------------- // Parsing support func (p *Parser) printTrace(a ...interface{}) { if !p.enableTrace { return } const dots = ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " const n = len(dots) fmt.Printf("%5d:%3d: ", p.tok.Pos.Line, p.tok.Pos.Column) i := 2 * p.indent for i > n { fmt.Print(dots) i -= n } // i <= n fmt.Print(dots[0:i]) fmt.Println(a...) } func trace(p *Parser, msg string) *Parser { p.printTrace(msg, "(") p.indent++ return p } // Usage pattern: defer un(trace(p, "...")) func un(p *Parser) { p.indent-- p.printTrace(")") } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/json/scanner/scanner.go ================================================ package scanner import ( "bytes" "fmt" "os" "unicode" "unicode/utf8" "github.com/hashicorp/hcl/json/token" ) // eof represents a marker rune for the end of the reader. const eof = rune(0) // Scanner defines a lexical scanner type Scanner struct { buf *bytes.Buffer // Source buffer for advancing and scanning src []byte // Source buffer for immutable access // Source Position srcPos token.Pos // current position prevPos token.Pos // previous position, used for peek() method lastCharLen int // length of last character in bytes lastLineLen int // length of last line in characters (for correct column reporting) tokStart int // token text start position tokEnd int // token text end position // Error is called for each error encountered. If no Error // function is set, the error is reported to os.Stderr. Error func(pos token.Pos, msg string) // ErrorCount is incremented by one for each error encountered. ErrorCount int // tokPos is the start position of most recently scanned token; set by // Scan. The Filename field is always left untouched by the Scanner. If // an error is reported (via Error) and Position is invalid, the scanner is // not inside a token. tokPos token.Pos } // New creates and initializes a new instance of Scanner using src as // its source content. func New(src []byte) *Scanner { // even though we accept a src, we read from a io.Reader compatible type // (*bytes.Buffer). So in the future we might easily change it to streaming // read. b := bytes.NewBuffer(src) s := &Scanner{ buf: b, src: src, } // srcPosition always starts with 1 s.srcPos.Line = 1 return s } // next reads the next rune from the bufferred reader. Returns the rune(0) if // an error occurs (or io.EOF is returned). func (s *Scanner) next() rune { ch, size, err := s.buf.ReadRune() if err != nil { // advance for error reporting s.srcPos.Column++ s.srcPos.Offset += size s.lastCharLen = size return eof } if ch == utf8.RuneError && size == 1 { s.srcPos.Column++ s.srcPos.Offset += size s.lastCharLen = size s.err("illegal UTF-8 encoding") return ch } // remember last position s.prevPos = s.srcPos s.srcPos.Column++ s.lastCharLen = size s.srcPos.Offset += size if ch == '\n' { s.srcPos.Line++ s.lastLineLen = s.srcPos.Column s.srcPos.Column = 0 } // debug // fmt.Printf("ch: %q, offset:column: %d:%d\n", ch, s.srcPos.Offset, s.srcPos.Column) return ch } // unread unreads the previous read Rune and updates the source position func (s *Scanner) unread() { if err := s.buf.UnreadRune(); err != nil { panic(err) // this is user fault, we should catch it } s.srcPos = s.prevPos // put back last position } // peek returns the next rune without advancing the reader. func (s *Scanner) peek() rune { peek, _, err := s.buf.ReadRune() if err != nil { return eof } s.buf.UnreadRune() return peek } // Scan scans the next token and returns the token. func (s *Scanner) Scan() token.Token { ch := s.next() // skip white space for isWhitespace(ch) { ch = s.next() } var tok token.Type // token text markings s.tokStart = s.srcPos.Offset - s.lastCharLen // token position, initial next() is moving the offset by one(size of rune // actually), though we are interested with the starting point s.tokPos.Offset = s.srcPos.Offset - s.lastCharLen if s.srcPos.Column > 0 { // common case: last character was not a '\n' s.tokPos.Line = s.srcPos.Line s.tokPos.Column = s.srcPos.Column } else { // last character was a '\n' // (we cannot be at the beginning of the source // since we have called next() at least once) s.tokPos.Line = s.srcPos.Line - 1 s.tokPos.Column = s.lastLineLen } switch { case isLetter(ch): lit := s.scanIdentifier() if lit == "true" || lit == "false" { tok = token.BOOL } else if lit == "null" { tok = token.NULL } else { s.err("illegal char") } case isDecimal(ch): tok = s.scanNumber(ch) default: switch ch { case eof: tok = token.EOF case '"': tok = token.STRING s.scanString() case '.': tok = token.PERIOD ch = s.peek() if isDecimal(ch) { tok = token.FLOAT ch = s.scanMantissa(ch) ch = s.scanExponent(ch) } case '[': tok = token.LBRACK case ']': tok = token.RBRACK case '{': tok = token.LBRACE case '}': tok = token.RBRACE case ',': tok = token.COMMA case ':': tok = token.COLON case '-': if isDecimal(s.peek()) { ch := s.next() tok = s.scanNumber(ch) } else { s.err("illegal char") } default: s.err("illegal char: " + string(ch)) } } // finish token ending s.tokEnd = s.srcPos.Offset // create token literal var tokenText string if s.tokStart >= 0 { tokenText = string(s.src[s.tokStart:s.tokEnd]) } s.tokStart = s.tokEnd // ensure idempotency of tokenText() call return token.Token{ Type: tok, Pos: s.tokPos, Text: tokenText, } } // scanNumber scans a HCL number definition starting with the given rune func (s *Scanner) scanNumber(ch rune) token.Type { zero := ch == '0' pos := s.srcPos s.scanMantissa(ch) ch = s.next() // seek forward if ch == 'e' || ch == 'E' { ch = s.scanExponent(ch) return token.FLOAT } if ch == '.' { ch = s.scanFraction(ch) if ch == 'e' || ch == 'E' { ch = s.next() ch = s.scanExponent(ch) } return token.FLOAT } if ch != eof { s.unread() } // If we have a larger number and this is zero, error if zero && pos != s.srcPos { s.err("numbers cannot start with 0") } return token.NUMBER } // scanMantissa scans the mantissa beginning from the rune. It returns the next // non decimal rune. It's used to determine wheter it's a fraction or exponent. func (s *Scanner) scanMantissa(ch rune) rune { scanned := false for isDecimal(ch) { ch = s.next() scanned = true } if scanned && ch != eof { s.unread() } return ch } // scanFraction scans the fraction after the '.' rune func (s *Scanner) scanFraction(ch rune) rune { if ch == '.' { ch = s.peek() // we peek just to see if we can move forward ch = s.scanMantissa(ch) } return ch } // scanExponent scans the remaining parts of an exponent after the 'e' or 'E' // rune. func (s *Scanner) scanExponent(ch rune) rune { if ch == 'e' || ch == 'E' { ch = s.next() if ch == '-' || ch == '+' { ch = s.next() } ch = s.scanMantissa(ch) } return ch } // scanString scans a quoted string func (s *Scanner) scanString() { braces := 0 for { // '"' opening already consumed // read character after quote ch := s.next() if ch == '\n' || ch < 0 || ch == eof { s.err("literal not terminated") return } if ch == '"' { break } // If we're going into a ${} then we can ignore quotes for awhile if braces == 0 && ch == '$' && s.peek() == '{' { braces++ s.next() } else if braces > 0 && ch == '{' { braces++ } if braces > 0 && ch == '}' { braces-- } if ch == '\\' { s.scanEscape() } } return } // scanEscape scans an escape sequence func (s *Scanner) scanEscape() rune { // http://en.cppreference.com/w/cpp/language/escape ch := s.next() // read character after '/' switch ch { case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\\', '"': // nothing to do case '0', '1', '2', '3', '4', '5', '6', '7': // octal notation ch = s.scanDigits(ch, 8, 3) case 'x': // hexademical notation ch = s.scanDigits(s.next(), 16, 2) case 'u': // universal character name ch = s.scanDigits(s.next(), 16, 4) case 'U': // universal character name ch = s.scanDigits(s.next(), 16, 8) default: s.err("illegal char escape") } return ch } // scanDigits scans a rune with the given base for n times. For example an // octal notation \184 would yield in scanDigits(ch, 8, 3) func (s *Scanner) scanDigits(ch rune, base, n int) rune { for n > 0 && digitVal(ch) < base { ch = s.next() n-- } if n > 0 { s.err("illegal char escape") } // we scanned all digits, put the last non digit char back s.unread() return ch } // scanIdentifier scans an identifier and returns the literal string func (s *Scanner) scanIdentifier() string { offs := s.srcPos.Offset - s.lastCharLen ch := s.next() for isLetter(ch) || isDigit(ch) || ch == '-' { ch = s.next() } if ch != eof { s.unread() // we got identifier, put back latest char } return string(s.src[offs:s.srcPos.Offset]) } // recentPosition returns the position of the character immediately after the // character or token returned by the last call to Scan. func (s *Scanner) recentPosition() (pos token.Pos) { pos.Offset = s.srcPos.Offset - s.lastCharLen switch { case s.srcPos.Column > 0: // common case: last character was not a '\n' pos.Line = s.srcPos.Line pos.Column = s.srcPos.Column case s.lastLineLen > 0: // last character was a '\n' // (we cannot be at the beginning of the source // since we have called next() at least once) pos.Line = s.srcPos.Line - 1 pos.Column = s.lastLineLen default: // at the beginning of the source pos.Line = 1 pos.Column = 1 } return } // err prints the error of any scanning to s.Error function. If the function is // not defined, by default it prints them to os.Stderr func (s *Scanner) err(msg string) { s.ErrorCount++ pos := s.recentPosition() if s.Error != nil { s.Error(pos, msg) return } fmt.Fprintf(os.Stderr, "%s: %s\n", pos, msg) } // isHexadecimal returns true if the given rune is a letter func isLetter(ch rune) bool { return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_' || ch >= 0x80 && unicode.IsLetter(ch) } // isHexadecimal returns true if the given rune is a decimal digit func isDigit(ch rune) bool { return '0' <= ch && ch <= '9' || ch >= 0x80 && unicode.IsDigit(ch) } // isHexadecimal returns true if the given rune is a decimal number func isDecimal(ch rune) bool { return '0' <= ch && ch <= '9' } // isHexadecimal returns true if the given rune is an hexadecimal number func isHexadecimal(ch rune) bool { return '0' <= ch && ch <= '9' || 'a' <= ch && ch <= 'f' || 'A' <= ch && ch <= 'F' } // isWhitespace returns true if the rune is a space, tab, newline or carriage return func isWhitespace(ch rune) bool { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' } // digitVal returns the integer value of a given octal,decimal or hexadecimal rune func digitVal(ch rune) int { switch { case '0' <= ch && ch <= '9': return int(ch - '0') case 'a' <= ch && ch <= 'f': return int(ch - 'a' + 10) case 'A' <= ch && ch <= 'F': return int(ch - 'A' + 10) } return 16 // larger than any legal digit val } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/json/token/position.go ================================================ package token import "fmt" // Pos describes an arbitrary source position // including the file, line, and column location. // A Position is valid if the line number is > 0. type Pos struct { Filename string // filename, if any Offset int // offset, starting at 0 Line int // line number, starting at 1 Column int // column number, starting at 1 (character count) } // IsValid returns true if the position is valid. func (p *Pos) IsValid() bool { return p.Line > 0 } // String returns a string in one of several forms: // // file:line:column valid position with file name // line:column valid position without file name // file invalid position with file name // - invalid position without file name func (p Pos) String() string { s := p.Filename if p.IsValid() { if s != "" { s += ":" } s += fmt.Sprintf("%d:%d", p.Line, p.Column) } if s == "" { s = "-" } return s } // Before reports whether the position p is before u. func (p Pos) Before(u Pos) bool { return u.Offset > p.Offset || u.Line > p.Line } // After reports whether the position p is after u. func (p Pos) After(u Pos) bool { return u.Offset < p.Offset || u.Line < p.Line } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/json/token/token.go ================================================ package token import ( "fmt" "strconv" hcltoken "github.com/hashicorp/hcl/hcl/token" ) // Token defines a single HCL token which can be obtained via the Scanner type Token struct { Type Type Pos Pos Text string } // Type is the set of lexical tokens of the HCL (HashiCorp Configuration Language) type Type int const ( // Special tokens ILLEGAL Type = iota EOF identifier_beg literal_beg NUMBER // 12345 FLOAT // 123.45 BOOL // true,false STRING // "abc" NULL // null literal_end identifier_end operator_beg LBRACK // [ LBRACE // { COMMA // , PERIOD // . COLON // : RBRACK // ] RBRACE // } operator_end ) var tokens = [...]string{ ILLEGAL: "ILLEGAL", EOF: "EOF", NUMBER: "NUMBER", FLOAT: "FLOAT", BOOL: "BOOL", STRING: "STRING", NULL: "NULL", LBRACK: "LBRACK", LBRACE: "LBRACE", COMMA: "COMMA", PERIOD: "PERIOD", COLON: "COLON", RBRACK: "RBRACK", RBRACE: "RBRACE", } // String returns the string corresponding to the token tok. func (t Type) String() string { s := "" if 0 <= t && t < Type(len(tokens)) { s = tokens[t] } if s == "" { s = "token(" + strconv.Itoa(int(t)) + ")" } return s } // IsIdentifier returns true for tokens corresponding to identifiers and basic // type literals; it returns false otherwise. func (t Type) IsIdentifier() bool { return identifier_beg < t && t < identifier_end } // IsLiteral returns true for tokens corresponding to basic type literals; it // returns false otherwise. func (t Type) IsLiteral() bool { return literal_beg < t && t < literal_end } // IsOperator returns true for tokens corresponding to operators and // delimiters; it returns false otherwise. func (t Type) IsOperator() bool { return operator_beg < t && t < operator_end } // String returns the token's literal text. Note that this is only // applicable for certain token types, such as token.IDENT, // token.STRING, etc.. func (t Token) String() string { return fmt.Sprintf("%s %s %s", t.Pos.String(), t.Type.String(), t.Text) } // HCLToken converts this token to an HCL token. // // The token type must be a literal type or this will panic. func (t Token) HCLToken() hcltoken.Token { switch t.Type { case BOOL: return hcltoken.Token{Type: hcltoken.BOOL, Text: t.Text} case FLOAT: return hcltoken.Token{Type: hcltoken.FLOAT, Text: t.Text} case NULL: return hcltoken.Token{Type: hcltoken.STRING, Text: ""} case NUMBER: return hcltoken.Token{Type: hcltoken.NUMBER, Text: t.Text} case STRING: return hcltoken.Token{Type: hcltoken.STRING, Text: t.Text, JSON: true} default: panic(fmt.Sprintf("unimplemented HCLToken for type: %s", t.Type)) } } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/lex.go ================================================ package hcl import ( "unicode" "unicode/utf8" ) type lexModeValue byte const ( lexModeUnknown lexModeValue = iota lexModeHcl lexModeJson ) // lexMode returns whether we're going to be parsing in JSON // mode or HCL mode. func lexMode(v []byte) lexModeValue { var ( r rune w int offset int ) for { r, w = utf8.DecodeRune(v[offset:]) offset += w if unicode.IsSpace(r) { continue } if r == '{' { return lexModeJson } break } return lexModeHcl } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/hcl/parse.go ================================================ package hcl import ( "fmt" "github.com/hashicorp/hcl/hcl/ast" hclParser "github.com/hashicorp/hcl/hcl/parser" jsonParser "github.com/hashicorp/hcl/json/parser" ) // ParseBytes accepts as input byte slice and returns ast tree. // // Input can be either JSON or HCL func ParseBytes(in []byte) (*ast.File, error) { return parse(in, true) } // ParseString accepts input as a string and returns ast tree. func ParseString(input string) (*ast.File, error) { return parse([]byte(input), true) } func parse(in []byte, errorOnDuplicateKeys bool) (*ast.File, error) { switch lexMode(in) { case lexModeHcl: if !errorOnDuplicateKeys { return hclParser.ParseDontErrorOnDuplicateKeys(in) } return hclParser.Parse(in) case lexModeJson: return jsonParser.Parse(in) } return nil, fmt.Errorf("unknown config format") } // Parse parses the given input and returns the root object. // // The input format can be either HCL or JSON. func Parse(input string) (*ast.File, error) { return parse([]byte(input), true) } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/.copywrite.hcl ================================================ schema_version = 1 project { license = "MPL-2.0" copyright_year = 2024 header_ignore = [] } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/LICENSE ================================================ Copyright (c) 2015 HashiCorp, Inc. Mozilla Public License, version 2.0 1. Definitions 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means a. that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or b. that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: a. any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or b. any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: a. under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and b. under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: a. for any code that a Contributor has removed from Covered Software; or b. for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or c. under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: a. such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and b. You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. 6. Disclaimer of Warranty Covered Software is provided under this License on an "as is" basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer. 7. Limitation of Liability Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party's negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You. 8. Litigation Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/README.md ================================================ Vault API ================= This provides the `github.com/hashicorp/vault/api` package which contains code useful for interacting with a Vault server. For examples of how to use this module, see the [vault-examples](https://github.com/hashicorp/vault-examples) repo. For a step-by-step walkthrough on using these client libraries, see the [developer quickstart](https://developer.hashicorp.com/vault/docs/get-started/developer-qs). [![GoDoc](https://godoc.org/github.com/hashicorp/vault/api?status.png)](https://godoc.org/github.com/hashicorp/vault/api) ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/auth.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "fmt" ) // Auth is used to perform credential backend related operations. type Auth struct { c *Client } type AuthMethod interface { Login(ctx context.Context, client *Client) (*Secret, error) } // Auth is used to return the client for credential-backend API calls. func (c *Client) Auth() *Auth { return &Auth{c: c} } // Login sets up the required request body for login requests to the given auth // method's /login API endpoint, and then performs a write to it. After a // successful login, this method will automatically set the client's token to // the login response's ClientToken as well. // // The Secret returned is the authentication secret, which if desired can be // passed as input to the NewLifetimeWatcher method in order to start // automatically renewing the token. func (a *Auth) Login(ctx context.Context, authMethod AuthMethod) (*Secret, error) { if authMethod == nil { return nil, fmt.Errorf("no auth method provided for login") } return a.login(ctx, authMethod) } // MFALogin is a wrapper that helps satisfy Vault's MFA implementation. // If optional credentials are provided a single-phase login will be attempted // and the resulting Secret will contain a ClientToken if the authentication is successful. // The client's token will also be set accordingly. // // If no credentials are provided a two-phase MFA login will be assumed and the resulting // Secret will have a MFARequirement containing the MFARequestID to be used in a follow-up // call to `sys/mfa/validate` or by passing it to the method (*Auth).MFAValidate. func (a *Auth) MFALogin(ctx context.Context, authMethod AuthMethod, creds ...string) (*Secret, error) { if len(creds) > 0 { a.c.SetMFACreds(creds) return a.login(ctx, authMethod) } return a.twoPhaseMFALogin(ctx, authMethod) } // MFAValidate validates an MFA request using the appropriate payload and a secret containing // Auth.MFARequirement, like the one returned by MFALogin when credentials are not provided. // Upon successful validation the client token will be set accordingly. // // The Secret returned is the authentication secret, which if desired can be // passed as input to the NewLifetimeWatcher method in order to start // automatically renewing the token. func (a *Auth) MFAValidate(ctx context.Context, mfaSecret *Secret, payload map[string]interface{}) (*Secret, error) { if mfaSecret == nil || mfaSecret.Auth == nil || mfaSecret.Auth.MFARequirement == nil { return nil, fmt.Errorf("secret does not contain MFARequirements") } s, err := a.c.Sys().MFAValidateWithContext(ctx, mfaSecret.Auth.MFARequirement.MFARequestID, payload) if err != nil { return nil, err } return a.checkAndSetToken(s) } // login performs the (*AuthMethod).Login() with the configured client and checks that a ClientToken is returned func (a *Auth) login(ctx context.Context, authMethod AuthMethod) (*Secret, error) { s, err := authMethod.Login(ctx, a.c) if err != nil { return nil, fmt.Errorf("unable to log in to auth method: %w", err) } return a.checkAndSetToken(s) } // twoPhaseMFALogin performs the (*AuthMethod).Login() with the configured client // and checks that an MFARequirement is returned func (a *Auth) twoPhaseMFALogin(ctx context.Context, authMethod AuthMethod) (*Secret, error) { s, err := authMethod.Login(ctx, a.c) if err != nil { return nil, fmt.Errorf("unable to log in: %w", err) } if s == nil || s.Auth == nil || s.Auth.MFARequirement == nil { if s != nil { s.Warnings = append(s.Warnings, "expected secret to contain MFARequirements") } return s, fmt.Errorf("assumed two-phase MFA login, returned secret is missing MFARequirements") } return s, nil } func (a *Auth) checkAndSetToken(s *Secret) (*Secret, error) { if s == nil || s.Auth == nil || s.Auth.ClientToken == "" { if s != nil { s.Warnings = append(s.Warnings, "expected secret to contain ClientToken") } return s, fmt.Errorf("response did not return ClientToken, client token not set") } a.c.SetToken(s.Auth.ClientToken) return s, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/auth_token.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "net/http" ) // TokenAuth is used to perform token backend operations on Vault type TokenAuth struct { c *Client } // Token is used to return the client for token-backend API calls func (a *Auth) Token() *TokenAuth { return &TokenAuth{c: a.c} } func (c *TokenAuth) Create(opts *TokenCreateRequest) (*Secret, error) { return c.CreateWithContext(context.Background(), opts) } func (c *TokenAuth) CreateWithContext(ctx context.Context, opts *TokenCreateRequest) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPost, "/v1/auth/token/create") if err := r.SetJSONBody(opts); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() return ParseSecret(resp.Body) } func (c *TokenAuth) CreateOrphan(opts *TokenCreateRequest) (*Secret, error) { return c.CreateOrphanWithContext(context.Background(), opts) } func (c *TokenAuth) CreateOrphanWithContext(ctx context.Context, opts *TokenCreateRequest) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPost, "/v1/auth/token/create-orphan") if err := r.SetJSONBody(opts); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() return ParseSecret(resp.Body) } func (c *TokenAuth) CreateWithRole(opts *TokenCreateRequest, roleName string) (*Secret, error) { return c.CreateWithRoleWithContext(context.Background(), opts, roleName) } func (c *TokenAuth) CreateWithRoleWithContext(ctx context.Context, opts *TokenCreateRequest, roleName string) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPost, "/v1/auth/token/create/"+roleName) if err := r.SetJSONBody(opts); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() return ParseSecret(resp.Body) } func (c *TokenAuth) Lookup(token string) (*Secret, error) { return c.LookupWithContext(context.Background(), token) } func (c *TokenAuth) LookupWithContext(ctx context.Context, token string) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPost, "/v1/auth/token/lookup") if err := r.SetJSONBody(map[string]interface{}{ "token": token, }); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() return ParseSecret(resp.Body) } func (c *TokenAuth) LookupAccessor(accessor string) (*Secret, error) { return c.LookupAccessorWithContext(context.Background(), accessor) } func (c *TokenAuth) LookupAccessorWithContext(ctx context.Context, accessor string) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPost, "/v1/auth/token/lookup-accessor") if err := r.SetJSONBody(map[string]interface{}{ "accessor": accessor, }); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() return ParseSecret(resp.Body) } func (c *TokenAuth) LookupSelf() (*Secret, error) { return c.LookupSelfWithContext(context.Background()) } func (c *TokenAuth) LookupSelfWithContext(ctx context.Context) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, "/v1/auth/token/lookup-self") resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() return ParseSecret(resp.Body) } func (c *TokenAuth) RenewAccessor(accessor string, increment int) (*Secret, error) { return c.RenewAccessorWithContext(context.Background(), accessor, increment) } func (c *TokenAuth) RenewAccessorWithContext(ctx context.Context, accessor string, increment int) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPost, "/v1/auth/token/renew-accessor") if err := r.SetJSONBody(map[string]interface{}{ "accessor": accessor, "increment": increment, }); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() return ParseSecret(resp.Body) } func (c *TokenAuth) Renew(token string, increment int) (*Secret, error) { return c.RenewWithContext(context.Background(), token, increment) } func (c *TokenAuth) RenewWithContext(ctx context.Context, token string, increment int) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPut, "/v1/auth/token/renew") if err := r.SetJSONBody(map[string]interface{}{ "token": token, "increment": increment, }); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() return ParseSecret(resp.Body) } func (c *TokenAuth) RenewSelf(increment int) (*Secret, error) { return c.RenewSelfWithContext(context.Background(), increment) } func (c *TokenAuth) RenewSelfWithContext(ctx context.Context, increment int) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPut, "/v1/auth/token/renew-self") body := map[string]interface{}{"increment": increment} if err := r.SetJSONBody(body); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() return ParseSecret(resp.Body) } // RenewTokenAsSelf wraps RenewTokenAsSelfWithContext using context.Background. func (c *TokenAuth) RenewTokenAsSelf(token string, increment int) (*Secret, error) { return c.RenewTokenAsSelfWithContext(context.Background(), token, increment) } // RenewTokenAsSelfWithContext behaves like renew-self, but authenticates using a provided // token instead of the token attached to the client. func (c *TokenAuth) RenewTokenAsSelfWithContext(ctx context.Context, token string, increment int) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPut, "/v1/auth/token/renew-self") r.ClientToken = token body := map[string]interface{}{"increment": increment} if err := r.SetJSONBody(body); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() return ParseSecret(resp.Body) } // RevokeAccessor wraps RevokeAccessorWithContext using context.Background. func (c *TokenAuth) RevokeAccessor(accessor string) error { return c.RevokeAccessorWithContext(context.Background(), accessor) } // RevokeAccessorWithContext revokes a token associated with the given accessor // along with all the child tokens. func (c *TokenAuth) RevokeAccessorWithContext(ctx context.Context, accessor string) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPost, "/v1/auth/token/revoke-accessor") if err := r.SetJSONBody(map[string]interface{}{ "accessor": accessor, }); err != nil { return err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return err } defer resp.Body.Close() return nil } // RevokeOrphan wraps RevokeOrphanWithContext using context.Background. func (c *TokenAuth) RevokeOrphan(token string) error { return c.RevokeOrphanWithContext(context.Background(), token) } // RevokeOrphanWithContext revokes a token without revoking the tree underneath it (so // child tokens are orphaned rather than revoked) func (c *TokenAuth) RevokeOrphanWithContext(ctx context.Context, token string) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPut, "/v1/auth/token/revoke-orphan") if err := r.SetJSONBody(map[string]interface{}{ "token": token, }); err != nil { return err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return err } defer resp.Body.Close() return nil } // RevokeSelf wraps RevokeSelfWithContext using context.Background. func (c *TokenAuth) RevokeSelf(token string) error { return c.RevokeSelfWithContext(context.Background(), token) } // RevokeSelfWithContext revokes the token making the call. The `token` parameter is kept // for backwards compatibility but is ignored; only the client's set token has // an effect. func (c *TokenAuth) RevokeSelfWithContext(ctx context.Context, token string) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPut, "/v1/auth/token/revoke-self") resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return err } defer resp.Body.Close() return nil } // RevokeTree wraps RevokeTreeWithContext using context.Background. func (c *TokenAuth) RevokeTree(token string) error { return c.RevokeTreeWithContext(context.Background(), token) } // RevokeTreeWithContext is the "normal" revoke operation that revokes the given token and // the entire tree underneath -- all of its child tokens, their child tokens, // etc. func (c *TokenAuth) RevokeTreeWithContext(ctx context.Context, token string) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPut, "/v1/auth/token/revoke") if err := r.SetJSONBody(map[string]interface{}{ "token": token, }); err != nil { return err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return err } defer resp.Body.Close() return nil } // TokenCreateRequest is the options structure for creating a token. type TokenCreateRequest struct { ID string `json:"id,omitempty"` Policies []string `json:"policies,omitempty"` Metadata map[string]string `json:"meta,omitempty"` Lease string `json:"lease,omitempty"` TTL string `json:"ttl,omitempty"` ExplicitMaxTTL string `json:"explicit_max_ttl,omitempty"` Period string `json:"period,omitempty"` NoParent bool `json:"no_parent,omitempty"` NoDefaultPolicy bool `json:"no_default_policy,omitempty"` DisplayName string `json:"display_name"` NumUses int `json:"num_uses"` Renewable *bool `json:"renewable,omitempty"` Type string `json:"type"` EntityAlias string `json:"entity_alias"` } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/cliconfig/config.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package cliconfig import ( "fmt" "os" "github.com/hashicorp/go-multierror" "github.com/hashicorp/hcl" "github.com/hashicorp/hcl/hcl/ast" "github.com/mitchellh/go-homedir" ) const ( // defaultConfigPath is the default path to the configuration file defaultConfigPath = "~/.vault" // configPathEnv is the environment variable that can be used to // override where the Vault configuration is. configPathEnv = "VAULT_CONFIG_PATH" ) // Config is the CLI configuration for Vault that can be specified via // a `$HOME/.vault` file which is HCL-formatted (therefore HCL or JSON). type defaultConfig struct { // TokenHelper is the executable/command that is executed for storing // and retrieving the authentication token for the Vault CLI. If this // is not specified, then vault's internal token store will be used, which // stores the token on disk unencrypted. TokenHelper string `hcl:"token_helper"` } // loadConfig reads the configuration from the given path. If path is // empty, then the default path will be used, or the environment variable // if set. func loadConfig(path string) (config *defaultConfig, duplicate bool, err error) { if path == "" { path = defaultConfigPath } if v := os.Getenv(configPathEnv); v != "" { path = v } // NOTE: requires HOME env var to be set path, err = homedir.Expand(path) if err != nil { return nil, false, fmt.Errorf("error expanding config path %q: %w", path, err) } contents, err := os.ReadFile(path) if err != nil && !os.IsNotExist(err) { return nil, false, err } conf, duplicate, err := parseConfig(string(contents)) if err != nil { return nil, duplicate, fmt.Errorf("error parsing config file at %q: %w; ensure that the file is valid; Ansible Vault is known to conflict with it", path, err) } return conf, duplicate, nil } // parseConfig parses the given configuration as a string. func parseConfig(contents string) (config *defaultConfig, duplicate bool, err error) { // TODO (HCL_DUP_KEYS_DEPRECATION): on removal stage change this to a simple hcl.Parse, effectively treating // duplicate keys as an error. Also get rid of all of these "duplicate" named return values root, duplicate, err := parseAndCheckForDuplicateHclAttributes(contents) if err != nil { return nil, duplicate, err } // Top-level item should be the object list list, ok := root.Node.(*ast.ObjectList) if !ok { return nil, duplicate, fmt.Errorf("failed to parse config; does not contain a root object") } valid := map[string]struct{}{ "token_helper": {}, } var validationErrors error for _, item := range list.Items { key := item.Keys[0].Token.Value().(string) if _, ok := valid[key]; !ok { validationErrors = multierror.Append(validationErrors, fmt.Errorf("invalid key %q on line %d", key, item.Assign.Line)) } } if validationErrors != nil { return nil, duplicate, validationErrors } var c defaultConfig if err := hcl.DecodeObject(&c, list); err != nil { return nil, duplicate, err } return &c, duplicate, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/cliconfig/hcl_dup_attr_deprecation.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package cliconfig import ( "fmt" "os" "strconv" "strings" "github.com/hashicorp/hcl" "github.com/hashicorp/hcl/hcl/ast" hclParser "github.com/hashicorp/hcl/hcl/parser" ) // allowHclDuplicatesEnvVar is an environment variable that allows Vault to revert back to accepting HCL files with // duplicate attributes. It's temporary until we finish the deprecation process, at which point this will be removed const allowHclDuplicatesEnvVar = "VAULT_ALLOW_PENDING_REMOVAL_DUPLICATE_HCL_ATTRIBUTES" // parseAndCheckForDuplicateHclAttributes parses the input JSON/HCL file and if it is HCL it also checks // for duplicate keys in the HCL file, allowing callers to handle the issue accordingly. It now only accepts duplicate // // keys if the environment variable VAULT_ALLOW_PENDING_REMOVAL_DUPLICATE_HCL_ATTRIBUTES is set to true. In a future // // release we'll remove this function entirely and there will be no way to parse HCL files with duplicate keys. // // TODO (HCL_DUP_KEYS_DEPRECATION): remove once not used anymore func parseAndCheckForDuplicateHclAttributes(input string) (res *ast.File, duplicate bool, err error) { res, err = hcl.Parse(input) if err != nil && strings.Contains(err.Error(), "Each argument can only be defined once") { allowHclDuplicatesRaw := os.Getenv(allowHclDuplicatesEnvVar) if allowHclDuplicatesRaw == "" { // default is to not allow duplicates return nil, false, err } allowHclDuplicates, envParseErr := strconv.ParseBool(allowHclDuplicatesRaw) if envParseErr != nil { return nil, false, fmt.Errorf("error parsing %q environment variable: %w", allowHclDuplicatesEnvVar, err) } if !allowHclDuplicates { return nil, false, err } // if allowed by the environment variable, parse again without failing on duplicate attributes duplicate = true res, err = hclParser.ParseDontErrorOnDuplicateKeys([]byte(input)) } return res, duplicate, err } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/cliconfig/util.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package cliconfig import ( "github.com/hashicorp/vault/api/tokenhelper" ) // DefaultTokenHelper returns the token helper that is configured for Vault. // This helper should only be used for non-server CLI commands. func DefaultTokenHelper() (tokenhelper.TokenHelper, error) { config, _, err := DefaultTokenHelperCheckDuplicates() return config, err } // TODO (HCL_DUP_KEYS_DEPRECATION): eventually make this consider duplicates an error. Ideally we should remove it but // maybe we can't since it's become part of the API pkg. func DefaultTokenHelperCheckDuplicates() (helper tokenhelper.TokenHelper, duplicate bool, err error) { config, duplicate, err := loadConfig("") if err != nil { return nil, duplicate, err } path := config.TokenHelper if path == "" { helper, err = tokenhelper.NewInternalTokenHelper() return helper, duplicate, err } path, err = tokenhelper.ExternalTokenHelperPath(path) if err != nil { return nil, duplicate, err } return &tokenhelper.ExternalTokenHelper{BinaryPath: path}, duplicate, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/client.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "crypto/hmac" "crypto/sha256" "crypto/tls" "encoding/base64" "encoding/hex" "encoding/json" "fmt" "net" "net/http" "net/url" "os" "path" "strconv" "strings" "sync" "time" "unicode" "github.com/hashicorp/errwrap" "github.com/hashicorp/go-cleanhttp" "github.com/hashicorp/go-retryablehttp" "github.com/hashicorp/go-rootcerts" "github.com/hashicorp/go-secure-stdlib/parseutil" "github.com/hashicorp/go-secure-stdlib/strutil" "golang.org/x/net/http2" "golang.org/x/time/rate" ) const ( EnvVaultAddress = "VAULT_ADDR" EnvVaultAgentAddr = "VAULT_AGENT_ADDR" EnvVaultCACert = "VAULT_CACERT" EnvVaultCACertBytes = "VAULT_CACERT_BYTES" EnvVaultCAPath = "VAULT_CAPATH" EnvVaultClientCert = "VAULT_CLIENT_CERT" EnvVaultClientKey = "VAULT_CLIENT_KEY" EnvVaultClientTimeout = "VAULT_CLIENT_TIMEOUT" EnvVaultHeaders = "VAULT_HEADERS" EnvVaultSRVLookup = "VAULT_SRV_LOOKUP" EnvVaultSkipVerify = "VAULT_SKIP_VERIFY" EnvVaultNamespace = "VAULT_NAMESPACE" EnvVaultTLSServerName = "VAULT_TLS_SERVER_NAME" EnvVaultWrapTTL = "VAULT_WRAP_TTL" EnvVaultMaxRetries = "VAULT_MAX_RETRIES" EnvVaultToken = "VAULT_TOKEN" EnvVaultMFA = "VAULT_MFA" EnvRateLimit = "VAULT_RATE_LIMIT" EnvHTTPProxy = "VAULT_HTTP_PROXY" EnvVaultProxyAddr = "VAULT_PROXY_ADDR" EnvVaultDisableRedirects = "VAULT_DISABLE_REDIRECTS" HeaderIndex = "X-Vault-Index" HeaderForward = "X-Vault-Forward" HeaderInconsistent = "X-Vault-Inconsistent" // NamespaceHeaderName is the header set to specify which namespace the // request is indented for. NamespaceHeaderName = "X-Vault-Namespace" // AuthHeaderName is the name of the header containing the token. AuthHeaderName = "X-Vault-Token" // RequestHeaderName is the name of the header used by the Agent for // SSRF protection. RequestHeaderName = "X-Vault-Request" SnapshotHeaderName = "X-Vault-Recover-Snapshot-Id" RecoverSourcePathHeaderName = "X-Vault-Recover-Source-Path" TLSErrorString = "This error usually means that the server is running with TLS disabled\n" + "but the client is configured to use TLS. Please either enable TLS\n" + "on the server or run the client with -address set to an address\n" + "that uses the http protocol:\n\n" + " vault -address http://
\n\n" + "You can also set the VAULT_ADDR environment variable:\n\n\n" + " VAULT_ADDR=http://
vault \n\n" + "where
is replaced by the actual address to the server." ) // Deprecated values const ( EnvVaultAgentAddress = "VAULT_AGENT_ADDR" EnvVaultInsecure = "VAULT_SKIP_VERIFY" DefaultAddress = "https://127.0.0.1:8200" ) // WrappingLookupFunc is a function that, given an HTTP verb and a path, // returns an optional string duration to be used for response wrapping (e.g. // "15s", or simply "15"). The path will not begin with "/v1/" or "v1/" or "/", // however, end-of-path forward slashes are not trimmed, so must match your // called path precisely. Response wrapping will only be used when the return // value is not the empty string. type WrappingLookupFunc func(operation, path string) string // Config is used to configure the creation of the client. type Config struct { modifyLock sync.RWMutex // Address is the address of the Vault server. This should be a complete // URL such as "http://vault.example.com". If you need a custom SSL // cert or want to enable insecure mode, you need to specify a custom // HttpClient. Address string // AgentAddress is the address of the local Vault agent. This should be a // complete URL such as "http://vault.example.com". AgentAddress string // HttpClient is the HTTP client to use. Vault sets sane defaults for the // http.Client and its associated http.Transport created in DefaultConfig. // If you must modify Vault's defaults, it is suggested that you start with // that client and modify as needed rather than start with an empty client // (or http.DefaultClient). HttpClient *http.Client // MinRetryWait controls the minimum time to wait before retrying when a 5xx // error occurs. Defaults to 1000 milliseconds. MinRetryWait time.Duration // MaxRetryWait controls the maximum time to wait before retrying when a 5xx // error occurs. Defaults to 1500 milliseconds. MaxRetryWait time.Duration // MaxRetries controls the maximum number of times to retry when a 5xx // error occurs. Set to 0 to disable retrying. Defaults to 2 (for a total // of three tries). MaxRetries int // Timeout, given a non-negative value, will apply the request timeout // to each request function unless an earlier deadline is passed to the // request function through context.Context. Note that this timeout is // not applicable to Logical().ReadRaw* (raw response) functions. // Defaults to 60 seconds. Timeout time.Duration // If there is an error when creating the configuration, this will be the // error Error error // The Backoff function to use; a default is used if not provided Backoff retryablehttp.Backoff // The CheckRetry function to use; a default is used if not provided CheckRetry retryablehttp.CheckRetry // Logger is the leveled logger to provide to the retryable HTTP client. Logger retryablehttp.LeveledLogger // Limiter is the rate limiter used by the client. // If this pointer is nil, then there will be no limit set. // In contrast, if this pointer is set, even to an empty struct, // then that limiter will be used. Note that an empty Limiter // is equivalent blocking all events. Limiter *rate.Limiter // OutputCurlString causes the actual request to return an error of type // *OutputStringError. Type asserting the error message will allow // fetching a cURL-compatible string for the operation. // // Note: It is not thread-safe to set this and make concurrent requests // with the same client. Cloning a client will not clone this value. OutputCurlString bool // OutputPolicy causes the actual request to return an error of type // *OutputPolicyError. Type asserting the error message will display // an example of the required policy HCL needed for the operation. // // Note: It is not thread-safe to set this and make concurrent requests // with the same client. Cloning a client will not clone this value. OutputPolicy bool // curlCACert, curlCAPath, curlClientCert and curlClientKey are used to keep // track of the name of the TLS certs and keys when OutputCurlString is set. // Cloning a client will also not clone those values. curlCACert, curlCAPath string curlClientCert, curlClientKey string // SRVLookup enables the client to lookup the host through DNS SRV lookup SRVLookup bool // CloneHeaders ensures that the source client's headers are copied to // its clone. CloneHeaders bool // CloneToken from parent. CloneToken bool // CloneTLSConfig from parent (tls.Config). CloneTLSConfig bool // ReadYourWrites ensures isolated read-after-write semantics by // providing discovered cluster replication states in each request. // The shared state is automatically propagated to all Client clones. // // Note: Careful consideration should be made prior to enabling this setting // since there will be a performance penalty paid upon each request. // This feature requires Enterprise server-side. ReadYourWrites bool // DisableRedirects when set to true, will prevent the client from // automatically following a (single) redirect response to its initial // request. This behavior may be desirable if using Vault CLI on the server // side. // // Note: Disabling redirect following behavior could cause issues with // commands such as 'vault operator raft snapshot' as this redirects to the // primary node. DisableRedirects bool clientTLSConfig *tls.Config } // TLSConfig contains the parameters needed to configure TLS on the HTTP client // used to communicate with Vault. type TLSConfig struct { // CACert is the path to a PEM-encoded CA cert file to use to verify the // Vault server SSL certificate. It takes precedence over CACertBytes // and CAPath. CACert string // CACertBytes is a PEM-encoded certificate or bundle. It takes precedence // over CAPath. CACertBytes []byte // CAPath is the path to a directory of PEM-encoded CA cert files to verify // the Vault server SSL certificate. CAPath string // ClientCert is the path to the certificate for Vault communication ClientCert string // ClientKey is the path to the private key for Vault communication ClientKey string // TLSServerName, if set, is used to set the SNI host when connecting via // TLS. TLSServerName string // Insecure enables or disables SSL verification Insecure bool } // DefaultConfig returns a default configuration for the client. It is // safe to modify the return value of this function. // // The default Address is https://127.0.0.1:8200, but this can be overridden by // setting the `VAULT_ADDR` environment variable. // // If an error is encountered, the Error field on the returned *Config will be populated with the specific error. func DefaultConfig() *Config { config := &Config{ Address: DefaultAddress, HttpClient: cleanhttp.DefaultPooledClient(), Timeout: time.Second * 60, MinRetryWait: time.Millisecond * 1000, MaxRetryWait: time.Millisecond * 1500, MaxRetries: 2, Backoff: retryablehttp.RateLimitLinearJitterBackoff, } transport := config.HttpClient.Transport.(*http.Transport) transport.TLSHandshakeTimeout = 10 * time.Second transport.TLSClientConfig = &tls.Config{ MinVersion: tls.VersionTLS12, } if err := http2.ConfigureTransport(transport); err != nil { config.Error = err return config } if err := config.ReadEnvironment(); err != nil { config.Error = err return config } // Ensure redirects are not automatically followed // Note that this is sane for the API client as it has its own // redirect handling logic (and thus also for command/meta), // but in e.g. http_test actual redirect handling is necessary config.HttpClient.CheckRedirect = func(req *http.Request, via []*http.Request) error { // Returning this value causes the Go net library to not close the // response body and to nil out the error. Otherwise retry clients may // try three times on every redirect because it sees an error from this // function (to prevent redirects) passing through to it. return http.ErrUseLastResponse } return config } // configureTLS is a lock free version of ConfigureTLS that can be used in // ReadEnvironment where the lock is already hold func (c *Config) configureTLS(t *TLSConfig) error { if c.HttpClient == nil { c.HttpClient = DefaultConfig().HttpClient } transport, ok := c.HttpClient.Transport.(*http.Transport) if !ok { return fmt.Errorf( "unsupported HTTPClient transport type %T", c.HttpClient.Transport) } clientTLSConfig := transport.TLSClientConfig var clientCert tls.Certificate foundClientCert := false switch { case t.ClientCert != "" && t.ClientKey != "": var err error clientCert, err = tls.LoadX509KeyPair(t.ClientCert, t.ClientKey) if err != nil { return err } foundClientCert = true c.curlClientCert = t.ClientCert c.curlClientKey = t.ClientKey case t.ClientCert != "" || t.ClientKey != "": return fmt.Errorf("both client cert and client key must be provided") } if t.CACert != "" || len(t.CACertBytes) != 0 || t.CAPath != "" { c.curlCACert = t.CACert c.curlCAPath = t.CAPath rootConfig := &rootcerts.Config{ CAFile: t.CACert, CACertificate: t.CACertBytes, CAPath: t.CAPath, } if err := rootcerts.ConfigureTLS(clientTLSConfig, rootConfig); err != nil { return err } } if t.Insecure { clientTLSConfig.InsecureSkipVerify = true } if foundClientCert { // We use this function to ignore the server's preferential list of // CAs, otherwise any CA used for the cert auth backend must be in the // server's CA pool clientTLSConfig.GetClientCertificate = func(*tls.CertificateRequestInfo) (*tls.Certificate, error) { return &clientCert, nil } } if t.TLSServerName != "" { clientTLSConfig.ServerName = t.TLSServerName } c.clientTLSConfig = clientTLSConfig return nil } func (c *Config) TLSConfig() *tls.Config { c.modifyLock.RLock() defer c.modifyLock.RUnlock() return c.clientTLSConfig.Clone() } // ConfigureTLS takes a set of TLS configurations and applies those to the // HTTP client. func (c *Config) ConfigureTLS(t *TLSConfig) error { c.modifyLock.Lock() defer c.modifyLock.Unlock() return c.configureTLS(t) } // ReadEnvironment reads configuration information from the environment. If // there is an error, no configuration value is updated. func (c *Config) ReadEnvironment() error { var envAddress string var envAgentAddress string var envCACert string var envCACertBytes []byte var envCAPath string var envClientCert string var envClientKey string var envClientTimeout time.Duration var envInsecure bool var envTLSServerName string var envMaxRetries *uint64 var envSRVLookup bool var limit *rate.Limiter var envVaultProxy string var envVaultDisableRedirects bool // Parse the environment variables if v := os.Getenv(EnvVaultAddress); v != "" { envAddress = v } if v := os.Getenv(EnvVaultAgentAddr); v != "" { envAgentAddress = v } if v := os.Getenv(EnvVaultMaxRetries); v != "" { maxRetries, err := strconv.ParseUint(v, 10, 32) if err != nil { return err } envMaxRetries = &maxRetries } if v := os.Getenv(EnvVaultCACert); v != "" { envCACert = v } if v := os.Getenv(EnvVaultCACertBytes); v != "" { envCACertBytes = []byte(v) } if v := os.Getenv(EnvVaultCAPath); v != "" { envCAPath = v } if v := os.Getenv(EnvVaultClientCert); v != "" { envClientCert = v } if v := os.Getenv(EnvVaultClientKey); v != "" { envClientKey = v } if v := os.Getenv(EnvRateLimit); v != "" { rateLimit, burstLimit, err := parseRateLimit(v) if err != nil { return err } limit = rate.NewLimiter(rate.Limit(rateLimit), burstLimit) } if t := os.Getenv(EnvVaultClientTimeout); t != "" { clientTimeout, err := parseutil.ParseDurationSecond(t) if err != nil { return fmt.Errorf("could not parse %q", EnvVaultClientTimeout) } envClientTimeout = clientTimeout } if v := os.Getenv(EnvVaultSkipVerify); v != "" { var err error envInsecure, err = strconv.ParseBool(v) if err != nil { return fmt.Errorf("could not parse %s", EnvVaultSkipVerify) } } if v := os.Getenv(EnvVaultSRVLookup); v != "" { var err error envSRVLookup, err = strconv.ParseBool(v) if err != nil { return fmt.Errorf("could not parse %s", EnvVaultSRVLookup) } } if v := os.Getenv(EnvVaultTLSServerName); v != "" { envTLSServerName = v } if v := os.Getenv(EnvHTTPProxy); v != "" { envVaultProxy = v } // VAULT_PROXY_ADDR supersedes VAULT_HTTP_PROXY if v := os.Getenv(EnvVaultProxyAddr); v != "" { envVaultProxy = v } if v := os.Getenv(EnvVaultDisableRedirects); v != "" { var err error envVaultDisableRedirects, err = strconv.ParseBool(v) if err != nil { return fmt.Errorf("could not parse %s", EnvVaultDisableRedirects) } c.DisableRedirects = envVaultDisableRedirects } // Configure the HTTP clients TLS configuration. t := &TLSConfig{ CACert: envCACert, CACertBytes: envCACertBytes, CAPath: envCAPath, ClientCert: envClientCert, ClientKey: envClientKey, TLSServerName: envTLSServerName, Insecure: envInsecure, } c.modifyLock.Lock() defer c.modifyLock.Unlock() c.SRVLookup = envSRVLookup c.Limiter = limit if err := c.configureTLS(t); err != nil { return err } if envAddress != "" { c.Address = envAddress } if envAgentAddress != "" { c.AgentAddress = envAgentAddress } if envMaxRetries != nil { c.MaxRetries = int(*envMaxRetries) } if envClientTimeout != 0 { c.Timeout = envClientTimeout } if envVaultProxy != "" { u, err := url.Parse(envVaultProxy) if err != nil { return err } transport := c.HttpClient.Transport.(*http.Transport) transport.Proxy = http.ProxyURL(u) } return nil } // ParseAddress transforms the provided address into a url.URL and handles // the case of Unix domain sockets by setting the DialContext in the // configuration's HttpClient.Transport. This function must be called with // c.modifyLock held for write access. func (c *Config) ParseAddress(address string) (*url.URL, error) { u, err := url.Parse(address) if err != nil { return nil, err } previousAddress := c.Address c.Address = address if strings.HasPrefix(address, "unix://") { // When the address begins with unix://, always change the transport's // DialContext (to match previous behaviour) socket := strings.TrimPrefix(address, "unix://") if transport, ok := c.HttpClient.Transport.(*http.Transport); ok { transport.DialContext = func(context.Context, string, string) (net.Conn, error) { return net.Dial("unix", socket) } // Since the address points to a unix domain socket, the scheme in the // *URL would be set to `unix`. The *URL in the client is expected to // be pointing to the protocol used in the application layer and not to // the transport layer. Hence, setting the fields accordingly. u.Scheme = "http" u.Host = "localhost" u.Path = "" } else { return nil, fmt.Errorf("attempting to specify unix:// address with non-transport transport") } } else if strings.HasPrefix(previousAddress, "unix://") { // When the address being set does not begin with unix:// but the previous // address in the Config did, change the transport's DialContext back to // use the default configuration that cleanhttp uses. if transport, ok := c.HttpClient.Transport.(*http.Transport); ok { transport.DialContext = cleanhttp.DefaultPooledTransport().DialContext } } return u, nil } func parseRateLimit(val string) (rate float64, burst int, err error) { _, err = fmt.Sscanf(val, "%f:%d", &rate, &burst) if err != nil { rate, err = strconv.ParseFloat(val, 64) if err != nil { err = fmt.Errorf("%v was provided but incorrectly formatted", EnvRateLimit) } burst = int(rate) } return rate, burst, err } // Client is the client to the Vault API. Create a client with NewClient. type Client struct { modifyLock sync.RWMutex addr *url.URL config *Config token string headers http.Header wrappingLookupFunc WrappingLookupFunc mfaCreds []string policyOverride bool requestCallbacks []RequestCallback responseCallbacks []ResponseCallback replicationStateStore *replicationStateStore hcpCookie *http.Cookie } // NewClient returns a new client for the given configuration. // // If the configuration is nil, Vault will use configuration from // DefaultConfig(), which is the recommended starting configuration. // // If the environment variable `VAULT_TOKEN` is present, the token will be // automatically added to the client. Otherwise, you must manually call // `SetToken()`. func NewClient(c *Config) (*Client, error) { def := DefaultConfig() if def == nil { return nil, fmt.Errorf("could not create/read default configuration") } if def.Error != nil { return nil, errwrap.Wrapf("error encountered setting up default configuration: {{err}}", def.Error) } if c == nil { c = def } c.modifyLock.Lock() defer c.modifyLock.Unlock() if c.MinRetryWait == 0 { c.MinRetryWait = def.MinRetryWait } if c.MaxRetryWait == 0 { c.MaxRetryWait = def.MaxRetryWait } if c.HttpClient == nil { c.HttpClient = def.HttpClient } if c.HttpClient.Transport == nil { c.HttpClient.Transport = def.HttpClient.Transport } address := c.Address if c.AgentAddress != "" { address = c.AgentAddress } u, err := c.ParseAddress(address) if err != nil { return nil, err } client := &Client{ addr: u, config: c, headers: make(http.Header), } if c.ReadYourWrites { client.replicationStateStore = &replicationStateStore{} } // Add the VaultRequest SSRF protection header client.headers[RequestHeaderName] = []string{"true"} if token := os.Getenv(EnvVaultToken); token != "" { client.token = token } if namespace := os.Getenv(EnvVaultNamespace); namespace != "" { client.setNamespace(namespace) } if envHeaders := os.Getenv(EnvVaultHeaders); envHeaders != "" { var result map[string]any err := json.Unmarshal([]byte(envHeaders), &result) if err != nil { return nil, fmt.Errorf("could not unmarshal environment-supplied headers") } var forbiddenHeaders []string for key, value := range result { if strings.HasPrefix(key, "X-Vault-") { forbiddenHeaders = append(forbiddenHeaders, key) continue } value, ok := value.(string) if !ok { return nil, fmt.Errorf("environment-supplied headers include non-string values") } client.AddHeader(key, value) } if len(forbiddenHeaders) > 0 { return nil, fmt.Errorf("failed to setup Headers[%s]: Header starting by 'X-Vault-' are for internal usage only", strings.Join(forbiddenHeaders, ", ")) } } return client, nil } func (c *Client) CloneConfig() *Config { c.modifyLock.RLock() defer c.modifyLock.RUnlock() newConfig := DefaultConfig() newConfig.Address = c.config.Address newConfig.AgentAddress = c.config.AgentAddress newConfig.MinRetryWait = c.config.MinRetryWait newConfig.MaxRetryWait = c.config.MaxRetryWait newConfig.MaxRetries = c.config.MaxRetries newConfig.Timeout = c.config.Timeout newConfig.Backoff = c.config.Backoff newConfig.CheckRetry = c.config.CheckRetry newConfig.Logger = c.config.Logger newConfig.Limiter = c.config.Limiter newConfig.SRVLookup = c.config.SRVLookup newConfig.CloneHeaders = c.config.CloneHeaders newConfig.CloneToken = c.config.CloneToken newConfig.ReadYourWrites = c.config.ReadYourWrites newConfig.clientTLSConfig = c.config.clientTLSConfig // we specifically want a _copy_ of the client here, not a pointer to the original one newClient := *c.config.HttpClient newConfig.HttpClient = &newClient return newConfig } // SetAddress sets the address of Vault in the client. The format of address should be // "://:". Setting this on a client will override the // value of VAULT_ADDR environment variable. func (c *Client) SetAddress(addr string) error { c.modifyLock.Lock() defer c.modifyLock.Unlock() parsedAddr, err := c.config.ParseAddress(addr) if err != nil { return fmt.Errorf("failed to set address: %w", err) } c.addr = parsedAddr return nil } // Address returns the Vault URL the client is configured to connect to func (c *Client) Address() string { c.modifyLock.RLock() defer c.modifyLock.RUnlock() return c.addr.String() } func (c *Client) SetCheckRedirect(f func(*http.Request, []*http.Request) error) { c.modifyLock.Lock() defer c.modifyLock.Unlock() c.config.modifyLock.Lock() defer c.config.modifyLock.Unlock() c.config.HttpClient.CheckRedirect = f } // SetLimiter will set the rate limiter for this client. // This method is thread-safe. // rateLimit and burst are specified according to https://godoc.org/golang.org/x/time/rate#NewLimiter func (c *Client) SetLimiter(rateLimit float64, burst int) { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.Lock() defer c.config.modifyLock.Unlock() c.config.Limiter = rate.NewLimiter(rate.Limit(rateLimit), burst) } func (c *Client) Limiter() *rate.Limiter { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.RLock() defer c.config.modifyLock.RUnlock() return c.config.Limiter } // SetMinRetryWait sets the minimum time to wait before retrying in the case of certain errors. func (c *Client) SetMinRetryWait(retryWait time.Duration) { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.Lock() defer c.config.modifyLock.Unlock() c.config.MinRetryWait = retryWait } func (c *Client) MinRetryWait() time.Duration { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.RLock() defer c.config.modifyLock.RUnlock() return c.config.MinRetryWait } // SetMaxRetryWait sets the maximum time to wait before retrying in the case of certain errors. func (c *Client) SetMaxRetryWait(retryWait time.Duration) { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.Lock() defer c.config.modifyLock.Unlock() c.config.MaxRetryWait = retryWait } func (c *Client) MaxRetryWait() time.Duration { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.RLock() defer c.config.modifyLock.RUnlock() return c.config.MaxRetryWait } // SetMaxRetries sets the number of retries that will be used in the case of certain errors func (c *Client) SetMaxRetries(retries int) { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.Lock() defer c.config.modifyLock.Unlock() c.config.MaxRetries = retries } func (c *Client) SetMaxIdleConnections(idle int) { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.Lock() defer c.config.modifyLock.Unlock() c.config.HttpClient.Transport.(*http.Transport).MaxIdleConns = idle } func (c *Client) MaxIdleConnections() int { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.Lock() defer c.config.modifyLock.Unlock() return c.config.HttpClient.Transport.(*http.Transport).MaxIdleConns } func (c *Client) SetDisableKeepAlives(disable bool) { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.Lock() defer c.config.modifyLock.Unlock() c.config.HttpClient.Transport.(*http.Transport).DisableKeepAlives = disable } func (c *Client) DisableKeepAlives() bool { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.RLock() defer c.config.modifyLock.RUnlock() return c.config.HttpClient.Transport.(*http.Transport).DisableKeepAlives } func (c *Client) MaxRetries() int { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.RLock() defer c.config.modifyLock.RUnlock() return c.config.MaxRetries } func (c *Client) SetSRVLookup(srv bool) { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.Lock() defer c.config.modifyLock.Unlock() c.config.SRVLookup = srv } func (c *Client) SRVLookup() bool { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.RLock() defer c.config.modifyLock.RUnlock() return c.config.SRVLookup } // SetCheckRetry sets the CheckRetry function to be used for future requests. func (c *Client) SetCheckRetry(checkRetry retryablehttp.CheckRetry) { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.Lock() defer c.config.modifyLock.Unlock() c.config.CheckRetry = checkRetry } func (c *Client) CheckRetry() retryablehttp.CheckRetry { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.RLock() defer c.config.modifyLock.RUnlock() return c.config.CheckRetry } // SetClientTimeout sets the client request timeout func (c *Client) SetClientTimeout(timeout time.Duration) { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.Lock() defer c.config.modifyLock.Unlock() c.config.Timeout = timeout } func (c *Client) ClientTimeout() time.Duration { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.RLock() defer c.config.modifyLock.RUnlock() return c.config.Timeout } func (c *Client) OutputCurlString() bool { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.RLock() defer c.config.modifyLock.RUnlock() return c.config.OutputCurlString } func (c *Client) SetOutputCurlString(curl bool) { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.Lock() defer c.config.modifyLock.Unlock() c.config.OutputCurlString = curl } func (c *Client) OutputPolicy() bool { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.RLock() defer c.config.modifyLock.RUnlock() return c.config.OutputPolicy } func (c *Client) SetOutputPolicy(isSet bool) { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.Lock() defer c.config.modifyLock.Unlock() c.config.OutputPolicy = isSet } // CurrentWrappingLookupFunc sets a lookup function that returns desired wrap TTLs // for a given operation and path. func (c *Client) CurrentWrappingLookupFunc() WrappingLookupFunc { c.modifyLock.RLock() defer c.modifyLock.RUnlock() return c.wrappingLookupFunc } // SetWrappingLookupFunc sets a lookup function that returns desired wrap TTLs // for a given operation and path. func (c *Client) SetWrappingLookupFunc(lookupFunc WrappingLookupFunc) { c.modifyLock.Lock() defer c.modifyLock.Unlock() c.wrappingLookupFunc = lookupFunc } // SetMFACreds sets the MFA credentials supplied either via the environment // variable or via the command line. func (c *Client) SetMFACreds(creds []string) { c.modifyLock.Lock() defer c.modifyLock.Unlock() c.mfaCreds = creds } // SetNamespace sets the namespace supplied either via the environment // variable or via the command line. func (c *Client) SetNamespace(namespace string) { c.modifyLock.Lock() defer c.modifyLock.Unlock() c.setNamespace(namespace) } func (c *Client) setNamespace(namespace string) { if c.headers == nil { c.headers = make(http.Header) } c.headers.Set(NamespaceHeaderName, namespace) } // ClearNamespace removes the namespace header if set. func (c *Client) ClearNamespace() { c.modifyLock.Lock() defer c.modifyLock.Unlock() if c.headers != nil { c.headers.Del(NamespaceHeaderName) } } // Namespace returns the namespace currently set in this client. It will // return an empty string if there is no namespace set. func (c *Client) Namespace() string { c.modifyLock.Lock() defer c.modifyLock.Unlock() if c.headers == nil { return "" } return c.headers.Get(NamespaceHeaderName) } // WithNamespace makes a shallow copy of Client, modifies it to use // the given namespace, and returns it. Passing an empty string will // temporarily unset the namespace. func (c *Client) WithNamespace(namespace string) *Client { c2 := *c c2.modifyLock = sync.RWMutex{} c.modifyLock.RLock() c2.headers = c.headersInternal() c.modifyLock.RUnlock() if namespace == "" { c2.ClearNamespace() } else { c2.SetNamespace(namespace) } return &c2 } // Token returns the access token being used by this client. It will // return the empty string if there is no token set. func (c *Client) Token() string { c.modifyLock.RLock() defer c.modifyLock.RUnlock() return c.token } // SetToken sets the token directly. This won't perform any auth // verification, it simply sets the token properly for future requests. func (c *Client) SetToken(v string) { c.modifyLock.Lock() defer c.modifyLock.Unlock() c.token = v } // HCPCookie returns the HCP cookie being used by this client. It will // return an empty cookie when no cookie is set. func (c *Client) HCPCookie() string { c.modifyLock.RLock() defer c.modifyLock.RUnlock() if c.hcpCookie == nil { return "" } return c.hcpCookie.String() } // SetHCPCookie sets the hcp cookie directly. This won't perform any auth // verification, it simply sets the token properly for future requests. func (c *Client) SetHCPCookie(v *http.Cookie) error { c.modifyLock.Lock() defer c.modifyLock.Unlock() if err := v.Valid(); err != nil { return err } c.hcpCookie = v return nil } // ClearToken deletes the token if it is set or does nothing otherwise. func (c *Client) ClearToken() { c.modifyLock.Lock() defer c.modifyLock.Unlock() c.token = "" } // Headers gets the current set of headers used for requests. This returns a // copy; to modify it call AddHeader or SetHeaders. func (c *Client) Headers() http.Header { c.modifyLock.RLock() defer c.modifyLock.RUnlock() return c.headersInternal() } // headersInternal gets the current set of headers used for requests. Must be called // with the read modifyLock held. func (c *Client) headersInternal() http.Header { if c.headers == nil { return nil } ret := make(http.Header) for k, v := range c.headers { for _, val := range v { ret[k] = append(ret[k], val) } } return ret } // AddHeader allows a single header key/value pair to be added // in a race-safe fashion. func (c *Client) AddHeader(key, value string) { c.modifyLock.Lock() defer c.modifyLock.Unlock() c.headers.Add(key, value) } // SetHeaders clears all previous headers and uses only the given // ones going forward. func (c *Client) SetHeaders(headers http.Header) { c.modifyLock.Lock() defer c.modifyLock.Unlock() c.headers = headers } // SetBackoff sets the backoff function to be used for future requests. func (c *Client) SetBackoff(backoff retryablehttp.Backoff) { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.Lock() defer c.config.modifyLock.Unlock() c.config.Backoff = backoff } func (c *Client) SetLogger(logger retryablehttp.LeveledLogger) { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.Lock() defer c.config.modifyLock.Unlock() c.config.Logger = logger } // SetCloneHeaders to allow headers to be copied whenever the client is cloned. func (c *Client) SetCloneHeaders(cloneHeaders bool) { c.modifyLock.Lock() defer c.modifyLock.Unlock() c.config.modifyLock.Lock() defer c.config.modifyLock.Unlock() c.config.CloneHeaders = cloneHeaders } // CloneHeaders gets the configured CloneHeaders value. func (c *Client) CloneHeaders() bool { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.RLock() defer c.config.modifyLock.RUnlock() return c.config.CloneHeaders } // SetCloneToken from parent func (c *Client) SetCloneToken(cloneToken bool) { c.modifyLock.Lock() defer c.modifyLock.Unlock() c.config.modifyLock.Lock() defer c.config.modifyLock.Unlock() c.config.CloneToken = cloneToken } // CloneToken gets the configured CloneToken value. func (c *Client) CloneToken() bool { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.RLock() defer c.config.modifyLock.RUnlock() return c.config.CloneToken } // SetReadYourWrites to prevent reading stale cluster replication state. func (c *Client) SetReadYourWrites(preventStaleReads bool) { c.modifyLock.Lock() defer c.modifyLock.Unlock() c.config.modifyLock.Lock() defer c.config.modifyLock.Unlock() if preventStaleReads { if c.replicationStateStore == nil { c.replicationStateStore = &replicationStateStore{} } } else { c.replicationStateStore = nil } c.config.ReadYourWrites = preventStaleReads } // ReadYourWrites gets the configured value of ReadYourWrites func (c *Client) ReadYourWrites() bool { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.RLock() defer c.config.modifyLock.RUnlock() return c.config.ReadYourWrites } // SetCloneTLSConfig from parent. func (c *Client) SetCloneTLSConfig(clone bool) { c.modifyLock.Lock() defer c.modifyLock.Unlock() c.config.modifyLock.Lock() defer c.config.modifyLock.Unlock() c.config.CloneTLSConfig = clone } // CloneTLSConfig gets the configured CloneTLSConfig value. func (c *Client) CloneTLSConfig() bool { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.RLock() defer c.config.modifyLock.RUnlock() return c.config.CloneTLSConfig } // Clone creates a new client with the same configuration. Note that the same // underlying http.Client is used; modifying the client from more than one // goroutine at once may not be safe, so modify the client as needed and then // clone. The headers are cloned based on the CloneHeaders property of the // source config // // Also, only the client's config is currently copied; this means items not in // the api.Config struct, such as policy override and wrapping function // behavior, must currently then be set as desired on the new client. func (c *Client) Clone() (*Client, error) { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.RLock() defer c.config.modifyLock.RUnlock() return c.clone(c.config.CloneHeaders) } // CloneWithHeaders creates a new client similar to Clone, with the difference // being that the headers are always cloned func (c *Client) CloneWithHeaders() (*Client, error) { c.modifyLock.RLock() defer c.modifyLock.RUnlock() c.config.modifyLock.RLock() defer c.config.modifyLock.RUnlock() return c.clone(true) } // clone creates a new client, with the headers being cloned based on the // passed in cloneheaders boolean. // Must be called with the read lock and config read lock held. func (c *Client) clone(cloneHeaders bool) (*Client, error) { config := c.config newConfig := &Config{ Address: config.Address, HttpClient: config.HttpClient, MinRetryWait: config.MinRetryWait, MaxRetryWait: config.MaxRetryWait, MaxRetries: config.MaxRetries, Timeout: config.Timeout, Backoff: config.Backoff, CheckRetry: config.CheckRetry, Logger: config.Logger, Limiter: config.Limiter, AgentAddress: config.AgentAddress, SRVLookup: config.SRVLookup, CloneHeaders: config.CloneHeaders, CloneToken: config.CloneToken, ReadYourWrites: config.ReadYourWrites, } if config.CloneTLSConfig { newConfig.clientTLSConfig = config.clientTLSConfig } client, err := NewClient(newConfig) if err != nil { return nil, err } if cloneHeaders { client.SetHeaders(c.headersInternal().Clone()) } if config.CloneToken { client.SetToken(c.token) } client.replicationStateStore = c.replicationStateStore return client, nil } // SetPolicyOverride sets whether requests should be sent with the policy // override flag to request overriding soft-mandatory Sentinel policies (both // RGPs and EGPs) func (c *Client) SetPolicyOverride(override bool) { c.modifyLock.Lock() defer c.modifyLock.Unlock() c.policyOverride = override } // NewRequest creates a new raw request object to query the Vault server // configured for this client. This is an advanced method and generally // doesn't need to be called externally. func (c *Client) NewRequest(method, requestPath string) *Request { c.modifyLock.RLock() addr := c.addr token := c.token mfaCreds := c.mfaCreds wrappingLookupFunc := c.wrappingLookupFunc policyOverride := c.policyOverride headers := c.headersInternal() c.modifyLock.RUnlock() host := addr.Host // if SRV records exist (see https://tools.ietf.org/html/draft-andrews-http-srv-02), lookup the SRV // record and take the highest match; this is not designed for high-availability, just discovery // Internet Draft specifies that the SRV record is ignored if a port is given if addr.Port() == "" && c.config.SRVLookup { _, addrs, err := net.LookupSRV("http", "tcp", addr.Hostname()) if err == nil && len(addrs) > 0 { host = fmt.Sprintf("%s:%d", addrs[0].Target, addrs[0].Port) } } req := &Request{ Method: method, URL: &url.URL{ User: addr.User, Scheme: addr.Scheme, Host: host, Path: path.Join(addr.Path, requestPath), }, Host: addr.Host, ClientToken: token, Params: make(map[string][]string), } req.HCPCookie = c.hcpCookie var lookupPath string switch { case strings.HasPrefix(requestPath, "/v1/"): lookupPath = strings.TrimPrefix(requestPath, "/v1/") case strings.HasPrefix(requestPath, "v1/"): lookupPath = strings.TrimPrefix(requestPath, "v1/") default: lookupPath = requestPath } req.MFAHeaderVals = mfaCreds if wrappingLookupFunc != nil { req.WrapTTL = wrappingLookupFunc(method, lookupPath) } else { req.WrapTTL = DefaultWrappingLookupFunc(method, lookupPath) } req.Headers = headers req.PolicyOverride = policyOverride return req } // RawRequest performs the raw request given. This request may be against // a Vault server not configured with this client. This is an advanced operation // that generally won't need to be called externally. // // Deprecated: RawRequest exists for historical compatibility and should not be // used directly. Use client.Logical().ReadRaw(...) or higher level methods // instead. func (c *Client) RawRequest(r *Request) (*Response, error) { return c.RawRequestWithContext(context.Background(), r) } // RawRequestWithContext performs the raw request given. This request may be against // a Vault server not configured with this client. This is an advanced operation // that generally won't need to be called externally. // // Deprecated: RawRequestWithContext exists for historical compatibility and // should not be used directly. Use client.Logical().ReadRawWithContext(...) // or higher level methods instead. func (c *Client) RawRequestWithContext(ctx context.Context, r *Request) (*Response, error) { // Note: we purposefully do not call cancel manually. The reason is // when canceled, the request.Body will EOF when reading due to the way // it streams data in. Cancel will still be run when the timeout is // hit, so this doesn't really harm anything. ctx, _ = c.withConfiguredTimeout(ctx) return c.rawRequestWithContext(ctx, r) } func (c *Client) rawRequestWithContext(ctx context.Context, r *Request) (*Response, error) { c.modifyLock.RLock() token := c.token c.config.modifyLock.RLock() limiter := c.config.Limiter minRetryWait := c.config.MinRetryWait maxRetryWait := c.config.MaxRetryWait maxRetries := c.config.MaxRetries checkRetry := c.config.CheckRetry backoff := c.config.Backoff httpClient := c.config.HttpClient ns := c.headers.Get(NamespaceHeaderName) outputCurlString := c.config.OutputCurlString outputPolicy := c.config.OutputPolicy logger := c.config.Logger disableRedirects := c.config.DisableRedirects c.config.modifyLock.RUnlock() c.modifyLock.RUnlock() // ensure that the most current namespace setting is used at the time of the call // e.g. calls using (*Client).WithNamespace switch ns { case "": r.Headers.Del(NamespaceHeaderName) default: r.Headers.Set(NamespaceHeaderName, ns) } for _, cb := range c.requestCallbacks { cb(r) } if c.config.ReadYourWrites { c.replicationStateStore.requireState(r) } if limiter != nil { limiter.Wait(ctx) } // check the token before potentially erroring from the API if err := validateToken(token); err != nil { return nil, err } redirectCount := 0 START: req, err := r.toRetryableHTTP() if err != nil { return nil, err } if req == nil { return nil, fmt.Errorf("nil request created") } if outputCurlString { // Note that although we're building this up here and returning it as an error object, the Error() // interface method on it only gets called in a context where the actual string returned from that // method is irrelevant, because it gets swallowed by an error buffer that's never output to the user. // That's on purpose, not a bug, because in this case, OutputStringError is not really an _error_, per se. // It's just a way of aborting the control flow so that requests don't actually execute, and instead, // we can detect what's happened back in the CLI machinery and show the actual curl string to the user. LastOutputStringError = &OutputStringError{ Request: req, TLSSkipVerify: c.config.HttpClient.Transport.(*http.Transport).TLSClientConfig.InsecureSkipVerify, ClientCert: c.config.curlClientCert, ClientKey: c.config.curlClientKey, ClientCACert: c.config.curlCACert, ClientCAPath: c.config.curlCAPath, } return nil, LastOutputStringError } if outputPolicy { LastOutputPolicyError = &OutputPolicyError{ method: req.Method, path: strings.TrimPrefix(req.URL.Path, "/v1"), params: req.URL.Query(), } return nil, LastOutputPolicyError } req.Request = req.Request.WithContext(ctx) if backoff == nil { backoff = retryablehttp.LinearJitterBackoff } if checkRetry == nil { checkRetry = DefaultRetryPolicy } client := &retryablehttp.Client{ HTTPClient: httpClient, RetryWaitMin: minRetryWait, RetryWaitMax: maxRetryWait, RetryMax: maxRetries, Backoff: backoff, CheckRetry: checkRetry, Logger: logger, ErrorHandler: retryablehttp.PassthroughErrorHandler, } var result *Response resp, err := client.Do(req) if resp != nil { result = &Response{Response: resp} } if err != nil { if strings.Contains(err.Error(), "tls: oversized") { err = errwrap.Wrapf("{{err}}\n\n"+TLSErrorString, err) } return result, err } // Check for a redirect, only allowing for a single redirect (if redirects aren't disabled) if (resp.StatusCode == 301 || resp.StatusCode == 302 || resp.StatusCode == 307) && redirectCount == 0 && !disableRedirects { // Parse the updated location respLoc, err := resp.Location() if err != nil { return result, err } // Ensure a protocol downgrade doesn't happen if req.URL.Scheme == "https" && respLoc.Scheme != "https" { return result, fmt.Errorf("redirect would cause protocol downgrade") } // Update the request r.URL = respLoc // Reset the request body if any if err := r.ResetJSONBody(); err != nil { return result, err } // Retry the request redirectCount++ goto START } if result != nil { for _, cb := range c.responseCallbacks { cb(result) } if c.config.ReadYourWrites { c.replicationStateStore.recordState(result) } } if err := result.Error(); err != nil { return result, err } return result, nil } // httpRequestWithContext avoids the use of the go-retryable library found in RawRequestWithContext and is // useful when making calls where a net/http client is desirable. A single redirect (status code 301, 302, // or 307) will be followed but all retry and timeout logic is the responsibility of the caller as is // closing the Response body. func (c *Client) httpRequestWithContext(ctx context.Context, r *Request) (*Response, error) { req, err := http.NewRequestWithContext(ctx, r.Method, r.URL.RequestURI(), r.Body) if err != nil { return nil, err } c.modifyLock.RLock() token := c.token c.config.modifyLock.RLock() limiter := c.config.Limiter httpClient := c.config.HttpClient outputCurlString := c.config.OutputCurlString outputPolicy := c.config.OutputPolicy disableRedirects := c.config.DisableRedirects // add headers if c.headers != nil { for header, vals := range c.headers { for _, val := range vals { req.Header.Add(header, val) } } // explicitly set the namespace header to current client if ns := c.headers.Get(NamespaceHeaderName); ns != "" { r.Headers.Set(NamespaceHeaderName, ns) } } c.config.modifyLock.RUnlock() c.modifyLock.RUnlock() // OutputCurlString and OutputPolicy logic rely on the request type to be retryable.Request if outputCurlString { return nil, fmt.Errorf("output-curl-string is not implemented for this request") } if outputPolicy { return nil, fmt.Errorf("output-policy is not implemented for this request") } req.URL.User = r.URL.User req.URL.Scheme = r.URL.Scheme req.URL.Host = r.URL.Host req.Host = r.URL.Host if len(r.ClientToken) != 0 { req.Header.Set(AuthHeaderName, r.ClientToken) } if len(r.WrapTTL) != 0 { req.Header.Set("X-Vault-Wrap-TTL", r.WrapTTL) } if len(r.MFAHeaderVals) != 0 { for _, mfaHeaderVal := range r.MFAHeaderVals { req.Header.Add("X-Vault-MFA", mfaHeaderVal) } } if r.PolicyOverride { req.Header.Set("X-Vault-Policy-Override", "true") } if limiter != nil { limiter.Wait(ctx) } // check the token before potentially erroring from the API if err := validateToken(token); err != nil { return nil, err } var result *Response resp, err := httpClient.Do(req) if resp != nil { result = &Response{Response: resp} } if err != nil { if strings.Contains(err.Error(), "tls: oversized") { err = errwrap.Wrapf("{{err}}\n\n"+TLSErrorString, err) } return result, err } // Check for a redirect, only allowing for a single redirect, if redirects aren't disabled if (resp.StatusCode == 301 || resp.StatusCode == 302 || resp.StatusCode == 307) && !disableRedirects { // Parse the updated location respLoc, err := resp.Location() if err != nil { return result, fmt.Errorf("redirect failed: %s", err) } // Ensure a protocol downgrade doesn't happen if req.URL.Scheme == "https" && respLoc.Scheme != "https" { return result, fmt.Errorf("redirect would cause protocol downgrade") } // Update the request req.URL = respLoc // Reset the request body if any if err := r.ResetJSONBody(); err != nil { return result, fmt.Errorf("redirect failed: %s", err) } // Retry the request resp, err = httpClient.Do(req) if err != nil { return result, fmt.Errorf("redirect failed: %s", err) } } if err := result.Error(); err != nil { return nil, err } return result, nil } type ( RequestCallback func(*Request) ResponseCallback func(*Response) ) // WithRequestCallbacks makes a shallow clone of Client, modifies it to use // the given callbacks, and returns it. Each of the callbacks will be invoked // on every outgoing request. A client may be used to issue requests // concurrently; any locking needed by callbacks invoked concurrently is the // callback's responsibility. func (c *Client) WithRequestCallbacks(callbacks ...RequestCallback) *Client { c2 := *c c2.modifyLock = sync.RWMutex{} c2.requestCallbacks = callbacks return &c2 } // WithResponseCallbacks makes a shallow clone of Client, modifies it to use // the given callbacks, and returns it. Each of the callbacks will be invoked // on every received response. A client may be used to issue requests // concurrently; any locking needed by callbacks invoked concurrently is the // callback's responsibility. func (c *Client) WithResponseCallbacks(callbacks ...ResponseCallback) *Client { c2 := *c c2.modifyLock = sync.RWMutex{} c2.responseCallbacks = callbacks return &c2 } // withConfiguredTimeout wraps the context with a timeout from the client configuration. func (c *Client) withConfiguredTimeout(ctx context.Context) (context.Context, context.CancelFunc) { timeout := c.ClientTimeout() if timeout > 0 { return context.WithTimeout(ctx, timeout) } return ctx, func() {} } // RecordState returns a response callback that will record the state returned // by Vault in a response header. func RecordState(state *string) ResponseCallback { return func(resp *Response) { *state = resp.Header.Get(HeaderIndex) } } // RequireState returns a request callback that will add a request header to // specify the state we require of Vault. This state was obtained from a // response header seen previous, probably captured with RecordState. func RequireState(states ...string) RequestCallback { return func(req *Request) { for _, s := range states { req.Headers.Add(HeaderIndex, s) } } } // compareReplicationStates returns 1 if s1 is newer or identical, -1 if s1 is older, and 0 // if neither s1 or s2 is strictly greater. An error is returned if s1 or s2 // are invalid or from different clusters. func compareReplicationStates(s1, s2 string) (int, error) { w1, err := ParseReplicationState(s1, nil) if err != nil { return 0, err } w2, err := ParseReplicationState(s2, nil) if err != nil { return 0, err } if w1.ClusterID != w2.ClusterID { return 0, fmt.Errorf("can't compare replication states with different ClusterIDs") } switch { case w1.LocalIndex >= w2.LocalIndex && w1.ReplicatedIndex >= w2.ReplicatedIndex: return 1, nil // We've already handled the case where both are equal above, so really we're // asking here if one or both are lesser. case w1.LocalIndex <= w2.LocalIndex && w1.ReplicatedIndex <= w2.ReplicatedIndex: return -1, nil } return 0, nil } // MergeReplicationStates returns a merged array of replication states by iterating // through all states in `old`. An iterated state is merged to the result before `new` // based on the result of compareReplicationStates func MergeReplicationStates(old []string, new string) []string { if len(old) == 0 || len(old) > 2 { return []string{new} } var ret []string for _, o := range old { c, err := compareReplicationStates(o, new) if err != nil { return []string{new} } switch c { case 1: ret = append(ret, o) case -1: ret = append(ret, new) case 0: ret = append(ret, o, new) } } return strutil.RemoveDuplicates(ret, false) } type WALState struct { ClusterID string LocalIndex uint64 ReplicatedIndex uint64 } func ParseReplicationState(raw string, hmacKey []byte) (*WALState, error) { cooked, err := base64.StdEncoding.DecodeString(raw) if err != nil { return nil, err } s := string(cooked) lastIndex := strings.LastIndexByte(s, ':') if lastIndex == -1 { return nil, fmt.Errorf("invalid full state header format") } state, stateHMACRaw := s[:lastIndex], s[lastIndex+1:] stateHMAC, err := hex.DecodeString(stateHMACRaw) if err != nil { return nil, fmt.Errorf("invalid state header HMAC: %v, %w", stateHMACRaw, err) } if len(hmacKey) != 0 { hm := hmac.New(sha256.New, hmacKey) hm.Write([]byte(state)) if !hmac.Equal(hm.Sum(nil), stateHMAC) { return nil, fmt.Errorf("invalid state header HMAC (mismatch)") } } pieces := strings.Split(state, ":") if len(pieces) != 4 || pieces[0] != "v1" || pieces[1] == "" { return nil, fmt.Errorf("invalid state header format") } localIndex, err := strconv.ParseUint(pieces[2], 10, 64) if err != nil { return nil, fmt.Errorf("invalid local index in state header: %w", err) } replicatedIndex, err := strconv.ParseUint(pieces[3], 10, 64) if err != nil { return nil, fmt.Errorf("invalid replicated index in state header: %w", err) } return &WALState{ ClusterID: pieces[1], LocalIndex: localIndex, ReplicatedIndex: replicatedIndex, }, nil } // ForwardInconsistent returns a request callback that will add a request // header which says: if the state required isn't present on the node receiving // this request, forward it to the active node. This should be used in // conjunction with RequireState. func ForwardInconsistent() RequestCallback { return func(req *Request) { req.Headers.Set(HeaderInconsistent, "forward-active-node") } } // ForwardAlways returns a request callback which adds a header telling any // performance standbys handling the request to forward it to the active node. // This feature must be enabled in Vault's configuration. func ForwardAlways() RequestCallback { return func(req *Request) { req.Headers.Set(HeaderForward, "active-node") } } // DefaultRetryPolicy is the default retry policy used by new Client objects. // It is the same as retryablehttp.DefaultRetryPolicy except that it also retries // 412 requests, which are returned by Vault when a X-Vault-Index header isn't // satisfied. func DefaultRetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) { retry, err := retryablehttp.DefaultRetryPolicy(ctx, resp, err) if err != nil || retry { return retry, err } if resp != nil && resp.StatusCode == 412 { return true, nil } return false, nil } // replicationStateStore is used to track cluster replication states // in order to ensure proper read-after-write semantics for a Client. type replicationStateStore struct { m sync.RWMutex store []string } // recordState updates the store's replication states with the merger of all // states. func (w *replicationStateStore) recordState(resp *Response) { w.m.Lock() defer w.m.Unlock() newState := resp.Header.Get(HeaderIndex) if newState != "" { w.store = MergeReplicationStates(w.store, newState) } } // requireState updates the Request with the store's current replication states. func (w *replicationStateStore) requireState(req *Request) { w.m.RLock() defer w.m.RUnlock() for _, s := range w.store { req.Headers.Add(HeaderIndex, s) } } // states currently stored. func (w *replicationStateStore) states() []string { w.m.RLock() defer w.m.RUnlock() c := make([]string, len(w.store)) copy(c, w.store) return c } // validateToken will check for non-printable characters to prevent a call that will fail at the api func validateToken(t string) error { idx := strings.IndexFunc(t, func(c rune) bool { return !unicode.IsPrint(c) }) if idx != -1 { return fmt.Errorf("configured Vault token contains non-printable characters and cannot be used") } return nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/hcl_dup_attr_deprecation.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "fmt" "os" "strconv" "strings" "github.com/hashicorp/hcl" "github.com/hashicorp/hcl/hcl/ast" hclParser "github.com/hashicorp/hcl/hcl/parser" ) // allowHclDuplicatesEnvVar is an environment variable that allows Vault to revert back to accepting HCL files with // duplicate attributes. It's temporary until we finish the deprecation process, at which point this will be removed const allowHclDuplicatesEnvVar = "VAULT_ALLOW_PENDING_REMOVAL_DUPLICATE_HCL_ATTRIBUTES" // parseAndCheckForDuplicateHclAttributes parses the input JSON/HCL file and if it is HCL it also checks // for duplicate keys in the HCL file, allowing callers to handle the issue accordingly. It now only accepts duplicate // keys if the environment variable VAULT_ALLOW_PENDING_REMOVAL_DUPLICATE_HCL_ATTRIBUTES is set to true. In a future // release we'll remove this function entirely and there will be no way to parse HCL files with duplicate keys. // TODO (HCL_DUP_KEYS_DEPRECATION): remove once not used anymore func parseAndCheckForDuplicateHclAttributes(input string) (res *ast.File, duplicate bool, err error) { res, err = hcl.Parse(input) if err != nil && strings.Contains(err.Error(), "Each argument can only be defined once") { allowHclDuplicatesRaw := os.Getenv(allowHclDuplicatesEnvVar) if allowHclDuplicatesRaw == "" { // default is to not allow duplicates return nil, false, err } allowHclDuplicates, envParseErr := strconv.ParseBool(allowHclDuplicatesRaw) if envParseErr != nil { return nil, false, fmt.Errorf("error parsing %q environment variable: %w", allowHclDuplicatesEnvVar, err) } if !allowHclDuplicates { return nil, false, err } // if allowed by the environment variable, parse again without failing on duplicate attributes duplicate = true res, err = hclParser.ParseDontErrorOnDuplicateKeys([]byte(input)) } return res, duplicate, err } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/help.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "fmt" "net/http" ) // Help wraps HelpWithContext using context.Background. func (c *Client) Help(path string) (*Help, error) { return c.HelpWithContext(context.Background(), path) } // HelpWithContext reads the help information for the given path. func (c *Client) HelpWithContext(ctx context.Context, path string) (*Help, error) { ctx, cancelFunc := c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.NewRequest(http.MethodGet, fmt.Sprintf("/v1/%s", path)) r.Params.Add("help", "1") resp, err := c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() var result Help err = resp.DecodeJSON(&result) return &result, err } type Help struct { Help string `json:"help"` SeeAlso []string `json:"see_also"` OpenAPI map[string]interface{} `json:"openapi"` } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/kv.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import "errors" // ErrSecretNotFound is returned by KVv1 and KVv2 wrappers to indicate that the // secret is missing at the given location. var ErrSecretNotFound = errors.New("secret not found") // A KVSecret is a key-value secret returned by Vault's KV secrets engine, // and is the most basic type of secret stored in Vault. // // Data contains the key-value pairs of the secret itself, // while Metadata contains a subset of metadata describing // this particular version of the secret. // The Metadata field for a KV v1 secret will always be nil, as // metadata is only supported starting in KV v2. // // The Raw field can be inspected for information about the lease, // and passed to a LifetimeWatcher object for periodic renewal. type KVSecret struct { Data map[string]interface{} VersionMetadata *KVVersionMetadata CustomMetadata map[string]interface{} Raw *Secret } // KVv1 is used to return a client for reads and writes against // a KV v1 secrets engine in Vault. // // The mount path is the location where the target KV secrets engine resides // in Vault. // // While v1 is not necessarily deprecated, Vault development servers tend to // use v2 as the version of the KV secrets engine, as this is what's mounted // by default when a server is started in -dev mode. See the kvv2 struct. // // Learn more about the KV secrets engine here: // https://developer.hashicorp.com/vault/docs/secrets/kv func (c *Client) KVv1(mountPath string) *KVv1 { return &KVv1{c: c, mountPath: mountPath} } // KVv2 is used to return a client for reads and writes against // a KV v2 secrets engine in Vault. // // The mount path is the location where the target KV secrets engine resides // in Vault. // // Vault development servers tend to have "secret" as the mount path, // as these are the default settings when a server is started in -dev mode. // // Learn more about the KV secrets engine here: // https://developer.hashicorp.com/vault/docs/secrets/kv func (c *Client) KVv2(mountPath string) *KVv2 { return &KVv2{c: c, mountPath: mountPath} } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/kv_v1.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "fmt" ) type KVv1 struct { c *Client mountPath string } // Get returns a secret from the KV v1 secrets engine. func (kv *KVv1) Get(ctx context.Context, secretPath string) (*KVSecret, error) { pathToRead := fmt.Sprintf("%s/%s", kv.mountPath, secretPath) secret, err := kv.c.Logical().ReadWithContext(ctx, pathToRead) if err != nil { return nil, fmt.Errorf("error encountered while reading secret at %s: %w", pathToRead, err) } if secret == nil { return nil, fmt.Errorf("%w: at %s", ErrSecretNotFound, pathToRead) } return &KVSecret{ Data: secret.Data, VersionMetadata: nil, Raw: secret, }, nil } // Put inserts a key-value secret (e.g. {"password": "Hashi123"}) into the // KV v1 secrets engine. // // If the secret already exists, it will be overwritten. func (kv *KVv1) Put(ctx context.Context, secretPath string, data map[string]interface{}) error { pathToWriteTo := fmt.Sprintf("%s/%s", kv.mountPath, secretPath) _, err := kv.c.Logical().WriteWithContext(ctx, pathToWriteTo, data) if err != nil { return fmt.Errorf("error writing secret to %s: %w", pathToWriteTo, err) } return nil } // Delete deletes a secret from the KV v1 secrets engine. func (kv *KVv1) Delete(ctx context.Context, secretPath string) error { pathToDelete := fmt.Sprintf("%s/%s", kv.mountPath, secretPath) _, err := kv.c.Logical().DeleteWithContext(ctx, pathToDelete) if err != nil { return fmt.Errorf("error deleting secret at %s: %w", pathToDelete, err) } return nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/kv_v2.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "errors" "fmt" "net/http" "sort" "strconv" "time" "github.com/mitchellh/mapstructure" ) type KVv2 struct { c *Client mountPath string } // KVMetadata is the full metadata for a given KV v2 secret. type KVMetadata struct { CASRequired bool `mapstructure:"cas_required"` CreatedTime time.Time `mapstructure:"created_time"` CurrentVersion int `mapstructure:"current_version"` CustomMetadata map[string]interface{} `mapstructure:"custom_metadata"` DeleteVersionAfter time.Duration `mapstructure:"delete_version_after"` MaxVersions int `mapstructure:"max_versions"` OldestVersion int `mapstructure:"oldest_version"` UpdatedTime time.Time `mapstructure:"updated_time"` // Keys are stringified ints, e.g. "3". To get a sorted slice of version metadata, use GetVersionsAsList. Versions map[string]KVVersionMetadata `mapstructure:"versions"` Raw *Secret } // KVMetadataPutInput is the subset of metadata that can be replaced for a // KV v2 secret using the PutMetadata method. // // All fields should be explicitly provided, as any fields left unset in the // struct will be reset to their zero value. type KVMetadataPutInput struct { CASRequired bool CustomMetadata map[string]interface{} DeleteVersionAfter time.Duration MaxVersions int } // KVMetadataPatchInput is the subset of metadata that can be manually modified for // a KV v2 secret using the PatchMetadata method. // // The struct's fields are all pointers. A pointer to a field's zero // value (e.g. false for *bool) implies that field should be reset to its // zero value after update, whereas a field left as a nil pointer // (e.g. nil for *bool) implies the field should remain unchanged. // // Since maps are already pointers, use an empty map to remove all // custom metadata. type KVMetadataPatchInput struct { CASRequired *bool CustomMetadata map[string]interface{} DeleteVersionAfter *time.Duration MaxVersions *int } // KVVersionMetadata is a subset of metadata for a given version of a KV v2 secret. type KVVersionMetadata struct { Version int `mapstructure:"version"` CreatedTime time.Time `mapstructure:"created_time"` DeletionTime time.Time `mapstructure:"deletion_time"` Destroyed bool `mapstructure:"destroyed"` } // Currently supported options: WithOption, WithCheckAndSet, WithMethod type KVOption func() (key string, value interface{}) const ( KVOptionCheckAndSet = "cas" KVOptionMethod = "method" KVMergeMethodPatch = "patch" KVMergeMethodReadWrite = "rw" ) // WithOption can optionally be passed to provide generic options for a // KV request. Valid keys and values depend on the type of request. func WithOption(key string, value interface{}) KVOption { return func() (string, interface{}) { return key, value } } // WithCheckAndSet can optionally be passed to perform a check-and-set // operation on a KV request. If not set, the write will be allowed. // If cas is set to 0, a write will only be allowed if the key doesn't exist. // If set to non-zero, the write will only be allowed if the key’s current // version matches the version specified in the cas parameter. func WithCheckAndSet(cas int) KVOption { return WithOption(KVOptionCheckAndSet, cas) } // WithMergeMethod can optionally be passed to dictate which type of // patch to perform in a Patch request. If set to "patch", then an HTTP PATCH // request will be issued. If set to "rw", then a read will be performed, // then a local update, followed by a remote update. Defaults to "patch". func WithMergeMethod(method string) KVOption { return WithOption(KVOptionMethod, method) } // Get returns the latest version of a secret from the KV v2 secrets engine. // // If the latest version has been deleted, an error will not be thrown, but // the Data field on the returned secret will be nil, and the Metadata field // will contain the deletion time. func (kv *KVv2) Get(ctx context.Context, secretPath string) (*KVSecret, error) { pathToRead := fmt.Sprintf("%s/data/%s", kv.mountPath, secretPath) secret, err := kv.c.Logical().ReadWithContext(ctx, pathToRead) if err != nil { return nil, fmt.Errorf("error encountered while reading secret at %s: %w", pathToRead, err) } if secret == nil { return nil, fmt.Errorf("%w: at %s", ErrSecretNotFound, pathToRead) } kvSecret, err := extractDataAndVersionMetadata(secret) if err != nil { return nil, fmt.Errorf("error parsing secret at %s: %w", pathToRead, err) } kvSecret.CustomMetadata = extractCustomMetadata(secret) return kvSecret, nil } // GetVersion returns the data and metadata for a specific version of the // given secret. // // If that version has been deleted, the Data field on the // returned secret will be nil, and the Metadata field will contain the deletion time. // // GetVersionsAsList can provide a list of available versions sorted by // version number, while the response from GetMetadata contains them as a map. func (kv *KVv2) GetVersion(ctx context.Context, secretPath string, version int) (*KVSecret, error) { pathToRead := fmt.Sprintf("%s/data/%s", kv.mountPath, secretPath) queryParams := map[string][]string{"version": {strconv.Itoa(version)}} secret, err := kv.c.Logical().ReadWithDataWithContext(ctx, pathToRead, queryParams) if err != nil { return nil, err } if secret == nil { return nil, fmt.Errorf("%w: for version %d at %s", ErrSecretNotFound, version, pathToRead) } kvSecret, err := extractDataAndVersionMetadata(secret) if err != nil { return nil, fmt.Errorf("error parsing secret at %s: %w", pathToRead, err) } kvSecret.CustomMetadata = extractCustomMetadata(secret) return kvSecret, nil } // GetVersionsAsList returns a subset of the metadata for each version of the secret, sorted by version number. func (kv *KVv2) GetVersionsAsList(ctx context.Context, secretPath string) ([]KVVersionMetadata, error) { pathToRead := fmt.Sprintf("%s/metadata/%s", kv.mountPath, secretPath) secret, err := kv.c.Logical().ReadWithContext(ctx, pathToRead) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, fmt.Errorf("%w: no metadata at %s", ErrSecretNotFound, pathToRead) } md, err := extractFullMetadata(secret) if err != nil { return nil, fmt.Errorf("unable to extract metadata from secret to determine versions: %w", err) } versionsList := make([]KVVersionMetadata, 0, len(md.Versions)) for _, versionMetadata := range md.Versions { versionsList = append(versionsList, versionMetadata) } sort.Slice(versionsList, func(i, j int) bool { return versionsList[i].Version < versionsList[j].Version }) return versionsList, nil } // GetMetadata returns the full metadata for a given secret, including a map of // its existing versions and their respective creation/deletion times, etc. func (kv *KVv2) GetMetadata(ctx context.Context, secretPath string) (*KVMetadata, error) { pathToRead := fmt.Sprintf("%s/metadata/%s", kv.mountPath, secretPath) secret, err := kv.c.Logical().ReadWithContext(ctx, pathToRead) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, fmt.Errorf("%w: no metadata at %s", ErrSecretNotFound, pathToRead) } md, err := extractFullMetadata(secret) if err != nil { return nil, fmt.Errorf("unable to extract metadata from secret: %w", err) } return md, nil } // Put inserts a key-value secret (e.g. {"password": "Hashi123"}) // into the KV v2 secrets engine. // // If the secret already exists, a new version will be created // and the previous version can be accessed with the GetVersion method. // GetMetadata can provide a list of available versions. func (kv *KVv2) Put(ctx context.Context, secretPath string, data map[string]interface{}, opts ...KVOption) (*KVSecret, error) { pathToWriteTo := fmt.Sprintf("%s/data/%s", kv.mountPath, secretPath) wrappedData := map[string]interface{}{ "data": data, } // Add options such as check-and-set, etc. // We leave this as an optional arg so that most users // can just pass plain key-value secret data without // having to remember to put the extra layer "data" in there. options := make(map[string]interface{}) for _, opt := range opts { k, v := opt() options[k] = v } if len(opts) > 0 { wrappedData["options"] = options } secret, err := kv.c.Logical().WriteWithContext(ctx, pathToWriteTo, wrappedData) if err != nil { return nil, fmt.Errorf("error writing secret to %s: %w", pathToWriteTo, err) } if secret == nil { return nil, fmt.Errorf("%w: after writing to %s", ErrSecretNotFound, pathToWriteTo) } metadata, err := extractVersionMetadata(secret) if err != nil { return nil, fmt.Errorf("secret was written successfully, but unable to view version metadata from response: %w", err) } kvSecret := &KVSecret{ Data: nil, // secret.Data in this case is the metadata VersionMetadata: metadata, Raw: secret, } kvSecret.CustomMetadata = extractCustomMetadata(secret) return kvSecret, nil } // PutMetadata can be used to fully replace a subset of metadata fields for a // given KV v2 secret. All fields will replace the corresponding values on the Vault server. // Any fields left as nil will reset the field on the Vault server back to its zero value. // // To only partially replace the values of these metadata fields, use PatchMetadata. // // This method can also be used to create a new secret with just metadata and no secret data yet. func (kv *KVv2) PutMetadata(ctx context.Context, secretPath string, metadata KVMetadataPutInput) error { pathToWriteTo := fmt.Sprintf("%s/metadata/%s", kv.mountPath, secretPath) const ( casRequiredKey = "cas_required" deleteVersionAfterKey = "delete_version_after" maxVersionsKey = "max_versions" customMetadataKey = "custom_metadata" ) // convert values to a map we can pass to Logical metadataMap := make(map[string]interface{}) metadataMap[maxVersionsKey] = metadata.MaxVersions metadataMap[deleteVersionAfterKey] = metadata.DeleteVersionAfter.String() metadataMap[casRequiredKey] = metadata.CASRequired metadataMap[customMetadataKey] = metadata.CustomMetadata _, err := kv.c.Logical().WriteWithContext(ctx, pathToWriteTo, metadataMap) if err != nil { return fmt.Errorf("error writing secret metadata to %s: %w", pathToWriteTo, err) } return nil } // Patch additively updates the most recent version of a key-value secret, // differentiating it from Put which will fully overwrite the previous data. // Only the key-value pairs that are new or changing need to be provided. // // The WithMethod KVOption function can optionally be passed to dictate which // kind of patch to perform, as older Vault server versions (pre-1.9.0) may // only be able to use the old "rw" (read-then-write) style of partial update, // whereas newer Vault servers can use the default value of "patch" if the // client token's policy has the "patch" capability. func (kv *KVv2) Patch(ctx context.Context, secretPath string, newData map[string]interface{}, opts ...KVOption) (*KVSecret, error) { // determine patch method var patchMethod string var ok bool for _, opt := range opts { k, v := opt() if k == "method" { patchMethod, ok = v.(string) if !ok { return nil, fmt.Errorf("unsupported type provided for option value; value for patch method should be string \"rw\" or \"patch\"") } } } // Determine which kind of patch to use, // the newer HTTP Patch style or the older read-then-write style var kvs *KVSecret var err error switch patchMethod { case "rw": kvs, err = readThenWrite(ctx, kv.c, kv.mountPath, secretPath, newData) case "patch": kvs, err = mergePatch(ctx, kv.c, kv.mountPath, secretPath, newData, opts...) case "": kvs, err = mergePatch(ctx, kv.c, kv.mountPath, secretPath, newData, opts...) default: return nil, fmt.Errorf("unsupported patch method provided; value for patch method should be string \"rw\" or \"patch\"") } if err != nil { return nil, fmt.Errorf("unable to perform patch: %w", err) } if kvs == nil { return nil, fmt.Errorf("no secret was written to %s", secretPath) } return kvs, nil } // PatchMetadata can be used to replace just a subset of a secret's // metadata fields at a time, as opposed to PutMetadata which is used to // completely replace all fields on the previous metadata. func (kv *KVv2) PatchMetadata(ctx context.Context, secretPath string, metadata KVMetadataPatchInput) error { pathToWriteTo := fmt.Sprintf("%s/metadata/%s", kv.mountPath, secretPath) md, err := toMetadataMap(metadata) if err != nil { return fmt.Errorf("unable to create map for JSON merge patch request: %w", err) } _, err = kv.c.Logical().JSONMergePatch(ctx, pathToWriteTo, md) if err != nil { return fmt.Errorf("error patching metadata at %s: %w", pathToWriteTo, err) } return nil } // Delete deletes the most recent version of a secret from the KV v2 // secrets engine. To delete an older version, use DeleteVersions. func (kv *KVv2) Delete(ctx context.Context, secretPath string) error { pathToDelete := fmt.Sprintf("%s/data/%s", kv.mountPath, secretPath) _, err := kv.c.Logical().DeleteWithContext(ctx, pathToDelete) if err != nil { return fmt.Errorf("error deleting secret at %s: %w", pathToDelete, err) } return nil } // DeleteVersions deletes the specified versions of a secret from the KV v2 // secrets engine. To delete the latest version of a secret, just use Delete. func (kv *KVv2) DeleteVersions(ctx context.Context, secretPath string, versions []int) error { // verb and path are different when trying to delete past versions pathToDelete := fmt.Sprintf("%s/delete/%s", kv.mountPath, secretPath) if len(versions) == 0 { return nil } var versionsToDelete []string for _, version := range versions { versionsToDelete = append(versionsToDelete, strconv.Itoa(version)) } versionsMap := map[string]interface{}{ "versions": versionsToDelete, } _, err := kv.c.Logical().WriteWithContext(ctx, pathToDelete, versionsMap) if err != nil { return fmt.Errorf("error deleting secret at %s: %w", pathToDelete, err) } return nil } // DeleteMetadata deletes all versions and metadata of the secret at the // given path. func (kv *KVv2) DeleteMetadata(ctx context.Context, secretPath string) error { pathToDelete := fmt.Sprintf("%s/metadata/%s", kv.mountPath, secretPath) _, err := kv.c.Logical().DeleteWithContext(ctx, pathToDelete) if err != nil { return fmt.Errorf("error deleting secret metadata at %s: %w", pathToDelete, err) } return nil } // Undelete undeletes the given versions of a secret, restoring the data // so that it can be fetched again with Get requests. // // A list of existing versions can be retrieved using the GetVersionsAsList method. func (kv *KVv2) Undelete(ctx context.Context, secretPath string, versions []int) error { pathToUndelete := fmt.Sprintf("%s/undelete/%s", kv.mountPath, secretPath) data := map[string]interface{}{ "versions": versions, } _, err := kv.c.Logical().WriteWithContext(ctx, pathToUndelete, data) if err != nil { return fmt.Errorf("error undeleting secret metadata at %s: %w", pathToUndelete, err) } return nil } // Destroy permanently removes the specified secret versions' data // from the Vault server. If no secret exists at the given path, no // action will be taken. // // A list of existing versions can be retrieved using the GetVersionsAsList method. func (kv *KVv2) Destroy(ctx context.Context, secretPath string, versions []int) error { pathToDestroy := fmt.Sprintf("%s/destroy/%s", kv.mountPath, secretPath) data := map[string]interface{}{ "versions": versions, } _, err := kv.c.Logical().WriteWithContext(ctx, pathToDestroy, data) if err != nil { return fmt.Errorf("error destroying secret metadata at %s: %w", pathToDestroy, err) } return nil } // Rollback can be used to roll a secret back to a previous // non-deleted/non-destroyed version. That previous version becomes the // next/newest version for the path. func (kv *KVv2) Rollback(ctx context.Context, secretPath string, toVersion int) (*KVSecret, error) { // First, do a read to get the current version for check-and-set latest, err := kv.Get(ctx, secretPath) if err != nil { return nil, fmt.Errorf("unable to get latest version of secret: %w", err) } // Make sure a value already exists if latest == nil { return nil, fmt.Errorf("no secret was found: %w", err) } // Verify metadata found if latest.VersionMetadata == nil { return nil, fmt.Errorf("no metadata found; rollback can only be used on existing data") } // Now run it again and read the version we want to roll back to rollbackVersion, err := kv.GetVersion(ctx, secretPath, toVersion) if err != nil { return nil, fmt.Errorf("unable to get previous version %d of secret: %w", toVersion, err) } err = validateRollbackVersion(rollbackVersion) if err != nil { return nil, fmt.Errorf("invalid rollback version %d: %w", toVersion, err) } casVersion := latest.VersionMetadata.Version kvs, err := kv.Put(ctx, secretPath, rollbackVersion.Data, WithCheckAndSet(casVersion)) if err != nil { return nil, fmt.Errorf("unable to roll back to previous secret version: %w", err) } return kvs, nil } func extractCustomMetadata(secret *Secret) map[string]interface{} { // Logical Writes return the metadata directly, Reads return it nested inside the "metadata" key customMetadataInterface, ok := secret.Data["custom_metadata"] if !ok { metadataInterface := secret.Data["metadata"] metadataMap, ok := metadataInterface.(map[string]interface{}) if !ok { return nil } customMetadataInterface = metadataMap["custom_metadata"] } cm, ok := customMetadataInterface.(map[string]interface{}) if !ok { return nil } return cm } func extractDataAndVersionMetadata(secret *Secret) (*KVSecret, error) { // A nil map is a valid value for data: secret.Data will be nil when this // version of the secret has been deleted, but the metadata is still // available. var data map[string]interface{} if secret.Data != nil { dataInterface, ok := secret.Data["data"] if !ok { return nil, fmt.Errorf("missing expected 'data' element") } if dataInterface != nil { data, ok = dataInterface.(map[string]interface{}) if !ok { return nil, fmt.Errorf("unexpected type for 'data' element: %T (%#v)", data, data) } } } metadata, err := extractVersionMetadata(secret) if err != nil { return nil, fmt.Errorf("unable to get version metadata: %w", err) } return &KVSecret{ Data: data, VersionMetadata: metadata, Raw: secret, }, nil } func extractVersionMetadata(secret *Secret) (*KVVersionMetadata, error) { var metadata *KVVersionMetadata if secret.Data == nil { return nil, nil } // Logical Writes return the metadata directly, Reads return it nested inside the "metadata" key var metadataMap map[string]interface{} metadataInterface, ok := secret.Data["metadata"] if ok { metadataMap, ok = metadataInterface.(map[string]interface{}) if !ok { return nil, fmt.Errorf("unexpected type for 'metadata' element: %T (%#v)", metadataInterface, metadataInterface) } } else { metadataMap = secret.Data } // deletion_time usually comes in as an empty string which can't be // processed as time.RFC3339, so we reset it to a convertible value if metadataMap["deletion_time"] == "" { metadataMap["deletion_time"] = time.Time{} } d, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ DecodeHook: mapstructure.StringToTimeHookFunc(time.RFC3339), Result: &metadata, }) if err != nil { return nil, fmt.Errorf("error setting up decoder for API response: %w", err) } err = d.Decode(metadataMap) if err != nil { return nil, fmt.Errorf("error decoding metadata from API response into VersionMetadata: %w", err) } return metadata, nil } func extractFullMetadata(secret *Secret) (*KVMetadata, error) { var metadata *KVMetadata if secret.Data == nil { return nil, nil } if versions, ok := secret.Data["versions"]; ok { versionsMap := versions.(map[string]interface{}) if len(versionsMap) > 0 { for version, metadata := range versionsMap { metadataMap := metadata.(map[string]interface{}) // deletion_time usually comes in as an empty string which can't be // processed as time.RFC3339, so we reset it to a convertible value if metadataMap["deletion_time"] == "" { metadataMap["deletion_time"] = time.Time{} } versionInt, err := strconv.Atoi(version) if err != nil { return nil, fmt.Errorf("error converting version %s to integer: %w", version, err) } metadataMap["version"] = versionInt versionsMap[version] = metadataMap // save the updated copy of the metadata map } } secret.Data["versions"] = versionsMap // save the updated copy of the versions map } d, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ DecodeHook: mapstructure.ComposeDecodeHookFunc( mapstructure.StringToTimeHookFunc(time.RFC3339), mapstructure.StringToTimeDurationHookFunc(), ), Result: &metadata, }) if err != nil { return nil, fmt.Errorf("error setting up decoder for API response: %w", err) } err = d.Decode(secret.Data) if err != nil { return nil, fmt.Errorf("error decoding metadata from API response into KVMetadata: %w", err) } return metadata, nil } func validateRollbackVersion(rollbackVersion *KVSecret) error { // Make sure a value already exists if rollbackVersion == nil || rollbackVersion.Data == nil { return fmt.Errorf("no secret found") } // Verify metadata found if rollbackVersion.VersionMetadata == nil { return fmt.Errorf("no version metadata found; rollback only works on existing data") } // Verify it hasn't been deleted if !rollbackVersion.VersionMetadata.DeletionTime.IsZero() { return fmt.Errorf("cannot roll back to a version that has been deleted") } if rollbackVersion.VersionMetadata.Destroyed { return fmt.Errorf("cannot roll back to a version that has been destroyed") } // Verify old data found if rollbackVersion.Data == nil { return fmt.Errorf("no data found; rollback only works on existing data") } return nil } func mergePatch(ctx context.Context, client *Client, mountPath string, secretPath string, newData map[string]interface{}, opts ...KVOption) (*KVSecret, error) { pathToMergePatch := fmt.Sprintf("%s/data/%s", mountPath, secretPath) // take any other additional options provided // and pass them along to the patch request wrappedData := map[string]interface{}{ "data": newData, } options := make(map[string]interface{}) for _, opt := range opts { k, v := opt() options[k] = v } if len(opts) > 0 { wrappedData["options"] = options } secret, err := client.Logical().JSONMergePatch(ctx, pathToMergePatch, wrappedData) if err != nil { var re *ResponseError if errors.As(err, &re) { switch re.StatusCode { // 403 case http.StatusForbidden: return nil, fmt.Errorf("received 403 from Vault server; please ensure that token's policy has \"patch\" capability: %w", err) // 404 case http.StatusNotFound: return nil, fmt.Errorf("%w: performing merge patch to %s", ErrSecretNotFound, pathToMergePatch) // 405 case http.StatusMethodNotAllowed: // If it's a 405, that probably means the server is running a pre-1.9 // Vault version that doesn't support the HTTP PATCH method. // Fall back to the old way of doing it. return readThenWrite(ctx, client, mountPath, secretPath, newData) } } return nil, fmt.Errorf("error performing merge patch to %s: %w", pathToMergePatch, err) } metadata, err := extractVersionMetadata(secret) if err != nil { return nil, fmt.Errorf("secret was written successfully, but unable to view version metadata from response: %w", err) } kvSecret := &KVSecret{ Data: nil, // secret.Data in this case is the metadata VersionMetadata: metadata, Raw: secret, } kvSecret.CustomMetadata = extractCustomMetadata(secret) return kvSecret, nil } func readThenWrite(ctx context.Context, client *Client, mountPath string, secretPath string, newData map[string]interface{}) (*KVSecret, error) { // First, read the secret. existingVersion, err := client.KVv2(mountPath).Get(ctx, secretPath) if err != nil { return nil, fmt.Errorf("error reading secret as part of read-then-write patch operation: %w", err) } // Make sure the secret already exists if existingVersion == nil || existingVersion.Data == nil { return nil, fmt.Errorf("%w: at %s as part of read-then-write patch operation", ErrSecretNotFound, secretPath) } // Verify existing secret has metadata if existingVersion.VersionMetadata == nil { return nil, fmt.Errorf("no metadata found at %s; patch can only be used on existing data", secretPath) } // Copy new data over with existing data combinedData := existingVersion.Data for k, v := range newData { combinedData[k] = v } updatedSecret, err := client.KVv2(mountPath).Put(ctx, secretPath, combinedData, WithCheckAndSet(existingVersion.VersionMetadata.Version)) if err != nil { return nil, fmt.Errorf("error writing secret to %s: %w", secretPath, err) } return updatedSecret, nil } func toMetadataMap(patchInput KVMetadataPatchInput) (map[string]interface{}, error) { metadataMap := make(map[string]interface{}) const ( casRequiredKey = "cas_required" deleteVersionAfterKey = "delete_version_after" maxVersionsKey = "max_versions" customMetadataKey = "custom_metadata" ) // The KVMetadataPatchInput struct is designed to have pointer fields so that // the user can easily express the difference between explicitly setting a // field back to its zero value (e.g. false), as opposed to just having // the field remain unchanged (e.g. nil). This way, they only need to pass // the fields they want to change. if patchInput.MaxVersions != nil { metadataMap[maxVersionsKey] = *(patchInput.MaxVersions) } if patchInput.CASRequired != nil { metadataMap[casRequiredKey] = *(patchInput.CASRequired) } if patchInput.CustomMetadata != nil { if len(patchInput.CustomMetadata) == 0 { // empty non-nil map means delete all the keys metadataMap[customMetadataKey] = nil } else { metadataMap[customMetadataKey] = patchInput.CustomMetadata } } if patchInput.DeleteVersionAfter != nil { metadataMap[deleteVersionAfterKey] = patchInput.DeleteVersionAfter.String() } return metadataMap, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/lifetime_watcher.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "errors" "math/rand" "strings" "sync" "time" "github.com/cenkalti/backoff/v4" ) var ( ErrLifetimeWatcherMissingInput = errors.New("missing input") ErrLifetimeWatcherMissingSecret = errors.New("missing secret") ErrLifetimeWatcherNotRenewable = errors.New("secret is not renewable") ErrLifetimeWatcherNoSecretData = errors.New("returned empty secret data") // Deprecated; kept for compatibility ErrRenewerMissingInput = errors.New("missing input to renewer") ErrRenewerMissingSecret = errors.New("missing secret to renew") ErrRenewerNotRenewable = errors.New("secret is not renewable") ErrRenewerNoSecretData = errors.New("returned empty secret data") // DefaultLifetimeWatcherRenewBuffer is the default size of the buffer for renew // messages on the channel. DefaultLifetimeWatcherRenewBuffer = 5 // Deprecated: kept for backwards compatibility DefaultRenewerRenewBuffer = 5 ) //go:generate enumer -type=RenewBehavior -trimprefix=RenewBehavior type RenewBehavior uint const ( // RenewBehaviorIgnoreErrors means we will attempt to keep renewing until // we hit the lifetime threshold. It also ignores errors stemming from // passing a non-renewable lease in. In practice, this means you simply // reauthenticate/refetch credentials when the watcher exits. This is the // default. RenewBehaviorIgnoreErrors RenewBehavior = iota // RenewBehaviorRenewDisabled turns off renewal attempts entirely. This // allows you to simply watch lifetime and have the watcher return at a // reasonable threshold without actually making Vault calls. RenewBehaviorRenewDisabled // RenewBehaviorErrorOnErrors is the "legacy" behavior which always exits // on some kind of error RenewBehaviorErrorOnErrors ) // LifetimeWatcher is a process for watching lifetime of a secret. // // watcher, err := client.NewLifetimeWatcher(&LifetimeWatcherInput{ // Secret: mySecret, // }) // go watcher.Start() // defer watcher.Stop() // // for { // select { // case err := <-watcher.DoneCh(): // if err != nil { // log.Fatal(err) // } // // // Renewal is now over // case renewal := <-watcher.RenewCh(): // log.Printf("Successfully renewed: %#v", renewal) // } // } // // `DoneCh` will return if renewal fails, or if the remaining lease duration is // under a built-in threshold and either renewing is not extending it or // renewing is disabled. In both cases, the caller should attempt a re-read of // the secret. Clients should check the return value of the channel to see if // renewal was successful. type LifetimeWatcher struct { l sync.Mutex client *Client secret *Secret grace time.Duration random *rand.Rand increment int doneCh chan error renewCh chan *RenewOutput renewBehavior RenewBehavior stopped bool stopCh chan struct{} errLifetimeWatcherNotRenewable error errLifetimeWatcherNoSecretData error } // LifetimeWatcherInput is used as input to the renew function. type LifetimeWatcherInput struct { // Secret is the secret to renew Secret *Secret // DEPRECATED: this does not do anything. Grace time.Duration // Rand is the randomizer to use for underlying randomization. If not // provided, one will be generated and seeded automatically. If provided, it // is assumed to have already been seeded. Rand *rand.Rand // RenewBuffer is the size of the buffered channel where renew messages are // dispatched. RenewBuffer int // The new TTL, in seconds, that should be set on the lease. The TTL set // here may or may not be honored by the vault server, based on Vault // configuration or any associated max TTL values. If specified, the // minimum of this value and the remaining lease duration will be used // for grace period calculations. Increment int // RenewBehavior controls what happens when a renewal errors or the // passed-in secret is not renewable. RenewBehavior RenewBehavior } // RenewOutput is the metadata returned to the client (if it's listening) to // renew messages. type RenewOutput struct { // RenewedAt is the timestamp when the renewal took place (UTC). RenewedAt time.Time // Secret is the underlying renewal data. It's the same struct as all data // that is returned from Vault, but since this is renewal data, it will not // usually include the secret itself. Secret *Secret } // NewLifetimeWatcher creates a new renewer from the given input. func (c *Client) NewLifetimeWatcher(i *LifetimeWatcherInput) (*LifetimeWatcher, error) { if i == nil { return nil, ErrLifetimeWatcherMissingInput } secret := i.Secret if secret == nil { return nil, ErrLifetimeWatcherMissingSecret } random := i.Rand if random == nil { // NOTE: // Rather than a cryptographically secure random number generator (RNG), // the default behavior uses the math/rand package. The random number is // used to introduce a slight jitter when calculating the grace period // for a monitored secret monitoring. This is intended to stagger renewal // requests to the Vault server, but in a semi-predictable way, so there // is no need to use a cryptographically secure RNG. random = rand.New(rand.NewSource(int64(time.Now().Nanosecond()))) } renewBuffer := i.RenewBuffer if renewBuffer == 0 { renewBuffer = DefaultLifetimeWatcherRenewBuffer } return &LifetimeWatcher{ client: c, secret: secret, increment: i.Increment, random: random, doneCh: make(chan error, 1), renewCh: make(chan *RenewOutput, renewBuffer), renewBehavior: i.RenewBehavior, stopped: false, stopCh: make(chan struct{}), errLifetimeWatcherNotRenewable: ErrLifetimeWatcherNotRenewable, errLifetimeWatcherNoSecretData: ErrLifetimeWatcherNoSecretData, }, nil } // Deprecated: exists only for backwards compatibility. Calls // NewLifetimeWatcher, and sets compatibility flags. func (c *Client) NewRenewer(i *LifetimeWatcherInput) (*LifetimeWatcher, error) { if i == nil { return nil, ErrRenewerMissingInput } secret := i.Secret if secret == nil { return nil, ErrRenewerMissingSecret } renewer, err := c.NewLifetimeWatcher(i) if err != nil { return nil, err } renewer.renewBehavior = RenewBehaviorErrorOnErrors renewer.errLifetimeWatcherNotRenewable = ErrRenewerNotRenewable renewer.errLifetimeWatcherNoSecretData = ErrRenewerNoSecretData return renewer, err } // DoneCh returns the channel where the renewer will publish when renewal stops. // If there is an error, this will be an error. func (r *LifetimeWatcher) DoneCh() <-chan error { return r.doneCh } // RenewCh is a channel that receives a message when a successful renewal takes // place and includes metadata about the renewal. func (r *LifetimeWatcher) RenewCh() <-chan *RenewOutput { return r.renewCh } // Stop stops the renewer. func (r *LifetimeWatcher) Stop() { r.l.Lock() defer r.l.Unlock() if !r.stopped { close(r.stopCh) r.stopped = true } } // Start starts a background process for watching the lifetime of this secret. // If renewal is enabled, when the secret has auth data, this attempts to renew // the auth (token); When the secret has a lease, this attempts to renew the // lease. func (r *LifetimeWatcher) Start() { r.doneCh <- r.doRenew() } // Renew is for compatibility with the legacy api.Renewer. Calling Renew // simply chains to Start. func (r *LifetimeWatcher) Renew() { r.Start() } type renewFunc func(string, int) (*Secret, error) // doRenew is a helper for renewing authentication. func (r *LifetimeWatcher) doRenew() error { defaultInitialRetryInterval := 10 * time.Second switch { case r.secret.Auth != nil: return r.doRenewWithOptions(true, !r.secret.Auth.Renewable, r.secret.Auth.LeaseDuration, r.secret.Auth.ClientToken, r.client.Auth().Token().RenewTokenAsSelf, defaultInitialRetryInterval) default: return r.doRenewWithOptions(false, !r.secret.Renewable, r.secret.LeaseDuration, r.secret.LeaseID, r.client.Sys().Renew, defaultInitialRetryInterval) } } func (r *LifetimeWatcher) doRenewWithOptions(tokenMode bool, nonRenewable bool, initLeaseDuration int, credString string, renew renewFunc, initialRetryInterval time.Duration, ) error { if credString == "" || (nonRenewable && r.renewBehavior == RenewBehaviorErrorOnErrors) { return r.errLifetimeWatcherNotRenewable } initialTime := time.Now() priorDuration := time.Duration(initLeaseDuration) * time.Second r.calculateGrace(priorDuration, time.Duration(r.increment)*time.Second) var errorBackoff backoff.BackOff for { // Check if we are stopped. select { case <-r.stopCh: return nil default: } var remainingLeaseDuration time.Duration fallbackLeaseDuration := initialTime.Add(priorDuration).Sub(time.Now()) var renewal *Secret var err error switch { case nonRenewable || r.renewBehavior == RenewBehaviorRenewDisabled: // Can't or won't renew, just keep the same expiration so we exit // when it's re-authentication time remainingLeaseDuration = fallbackLeaseDuration default: // Renew the token renewal, err = renew(credString, r.increment) if err != nil && strings.Contains(err.Error(), "permission denied") { // We can't renew since the token doesn't have permission to. Fall back // to the code path for non-renewable tokens. nonRenewable = true continue } if err != nil || renewal == nil || (tokenMode && renewal.Auth == nil) { if r.renewBehavior == RenewBehaviorErrorOnErrors { if err != nil { return err } if renewal == nil || (tokenMode && renewal.Auth == nil) { return r.errLifetimeWatcherNoSecretData } } // Calculate remaining duration until initial token lease expires remainingLeaseDuration = initialTime.Add(time.Duration(initLeaseDuration) * time.Second).Sub(time.Now()) if errorBackoff == nil { errorBackoff = &backoff.ExponentialBackOff{ MaxElapsedTime: remainingLeaseDuration, RandomizationFactor: backoff.DefaultRandomizationFactor, InitialInterval: initialRetryInterval, MaxInterval: 5 * time.Minute, Multiplier: 2, Clock: backoff.SystemClock, } errorBackoff.Reset() } break } errorBackoff = nil // Push a message that a renewal took place. select { case r.renewCh <- &RenewOutput{time.Now().UTC(), renewal}: default: } // Possibly error if we are not renewable if ((tokenMode && !renewal.Auth.Renewable) || (!tokenMode && !renewal.Renewable)) && r.renewBehavior == RenewBehaviorErrorOnErrors { return r.errLifetimeWatcherNotRenewable } // Reset initial time initialTime = time.Now() // Grab the lease duration initLeaseDuration = renewal.LeaseDuration if tokenMode { initLeaseDuration = renewal.Auth.LeaseDuration } remainingLeaseDuration = time.Duration(initLeaseDuration) * time.Second } var sleepDuration time.Duration if errorBackoff == nil { sleepDuration = r.calculateSleepDuration(remainingLeaseDuration, priorDuration) } else { sleepDuration = errorBackoff.NextBackOff() if sleepDuration == backoff.Stop { return err } } // remainingLeaseDuration becomes the priorDuration for the next loop priorDuration = remainingLeaseDuration // If we are within grace, return now; or, if the amount of time we // would sleep would land us in the grace period. This helps with short // tokens; for example, you don't want a current lease duration of 4 // seconds, a grace period of 3 seconds, and end up sleeping for more // than three of those seconds and having a very small budget of time // to renew. if remainingLeaseDuration <= r.grace || remainingLeaseDuration-sleepDuration <= r.grace { return nil } timer := time.NewTimer(sleepDuration) select { case <-r.stopCh: timer.Stop() return nil case <-timer.C: continue } } } // calculateSleepDuration calculates the amount of time the LifeTimeWatcher should sleep // before re-entering its loop. func (r *LifetimeWatcher) calculateSleepDuration(remainingLeaseDuration, priorDuration time.Duration) time.Duration { // We keep evaluating a new grace period so long as the lease is // extending. Once it stops extending, we've hit the max and need to // rely on the grace duration. if remainingLeaseDuration > priorDuration { r.calculateGrace(remainingLeaseDuration, time.Duration(r.increment)*time.Second) } // The sleep duration is set to 2/3 of the current lease duration plus // 1/3 of the current grace period, which adds jitter. return time.Duration(float64(remainingLeaseDuration.Nanoseconds())*2/3 + float64(r.grace.Nanoseconds())/3) } // calculateGrace calculates the grace period based on the minimum of the // remaining lease duration and the token increment value; it also adds some // jitter to not have clients be in sync. func (r *LifetimeWatcher) calculateGrace(leaseDuration, increment time.Duration) { minDuration := leaseDuration if minDuration > increment && increment > 0 { minDuration = increment } if minDuration <= 0 { r.grace = 0 return } leaseNanos := float64(minDuration.Nanoseconds()) jitterMax := 0.1 * leaseNanos // For a given lease duration, we want to allow 80-90% of that to elapse, // so the remaining amount is the grace period r.grace = time.Duration(jitterMax) + time.Duration(uint64(r.random.Int63())%uint64(jitterMax)) } type ( Renewer = LifetimeWatcher RenewerInput = LifetimeWatcherInput ) ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/logical.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "bytes" "context" "encoding/json" "errors" "fmt" "io" "maps" "net/http" "net/url" "os" "strings" "github.com/hashicorp/errwrap" ) const ( wrappedResponseLocation = "cubbyhole/response" ) var ( // The default TTL that will be used with `sys/wrapping/wrap`, can be // changed DefaultWrappingTTL = "5m" // The default function used if no other function is set. It honors the env // var to set the wrap TTL. The default wrap TTL will apply when when writing // to `sys/wrapping/wrap` when the env var is not set. DefaultWrappingLookupFunc = func(operation, path string) string { if os.Getenv(EnvVaultWrapTTL) != "" { return os.Getenv(EnvVaultWrapTTL) } if (operation == http.MethodPut || operation == http.MethodPost) && path == "sys/wrapping/wrap" { return DefaultWrappingTTL } return "" } ) // Logical is used to perform logical backend operations on Vault. type Logical struct { c *Client } // Logical is used to return the client for logical-backend API calls. func (c *Client) Logical() *Logical { return &Logical{c: c} } func (c *Logical) Read(path string) (*Secret, error) { return c.ReadWithDataWithContext(context.Background(), path, nil) } func (c *Logical) ReadWithContext(ctx context.Context, path string) (*Secret, error) { return c.ReadWithDataWithContext(ctx, path, nil) } func (c *Logical) ReadWithData(path string, data map[string][]string) (*Secret, error) { return c.ReadWithDataWithContext(context.Background(), path, data) } // ReadFromSnapshot reads the data at the given Vault path from a previously // loaded snapshot. The snapshotID parameter is the ID of the loaded snapshot func (c *Logical) ReadFromSnapshot(path string, snapshotID string) (*Secret, error) { return c.ReadWithData(path, map[string][]string{"read_snapshot_id": {snapshotID}}) } func (c *Logical) ReadWithDataWithContext(ctx context.Context, path string, data map[string][]string) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() resp, err := c.readRawWithDataWithContext(ctx, path, data, nil) return c.ParseRawResponseAndCloseBody(resp, err) } // ReadWithRequest returns a Secret for the given LogicalReadRequest. This is a // more flexible version of ReadWithContext, which allows for passing extra // headers to the Vault server. func (c *Logical) ReadWithRequest(ctx context.Context, req LogicalReadRequest) (*Secret, error) { resp, err := c.readRawWithDataWithContext(ctx, req.Path(), req.Values(), req.Headers()) return c.ParseRawResponseAndCloseBody(resp, err) } // ReadRaw attempts to read the value stored at the given Vault path // (without '/v1/' prefix) and returns a raw *http.Response. // // Note: the raw-response functions do not respect the client-configured // request timeout; if a timeout is desired, please use ReadRawWithContext // instead and set the timeout through context.WithTimeout or context.WithDeadline. func (c *Logical) ReadRaw(path string) (*Response, error) { return c.ReadRawWithDataWithContext(context.Background(), path, nil) } // ReadRawWithContext attempts to read the value stored at the give Vault path // (without '/v1/' prefix) and returns a raw *http.Response. // // Note: the raw-response functions do not respect the client-configured // request timeout; if a timeout is desired, please set it through // context.WithTimeout or context.WithDeadline. func (c *Logical) ReadRawWithContext(ctx context.Context, path string) (*Response, error) { return c.ReadRawWithDataWithContext(ctx, path, nil) } // ReadRawWithData attempts to read the value stored at the given Vault // path (without '/v1/' prefix) and returns a raw *http.Response. The 'data' map // is added as query parameters to the request. // // Note: the raw-response functions do not respect the client-configured // request timeout; if a timeout is desired, please use // ReadRawWithDataWithContext instead and set the timeout through // context.WithTimeout or context.WithDeadline. func (c *Logical) ReadRawWithData(path string, data map[string][]string) (*Response, error) { return c.ReadRawWithDataWithContext(context.Background(), path, data) } func (c *Logical) ReadRawFromSnapshot(path string, snapshotID string) (*Response, error) { return c.ReadRawWithDataWithContext(context.Background(), path, map[string][]string{"read_snapshot_id": {snapshotID}}) } // ReadRawWithDataWithContext attempts to read the value stored at the given // Vault path (without '/v1/' prefix) and returns a raw *http.Response. The 'data' // map is added as query parameters to the request. // // Note: the raw-response functions do not respect the client-configured // request timeout; if a timeout is desired, please set it through // context.WithTimeout or context.WithDeadline. func (c *Logical) ReadRawWithDataWithContext(ctx context.Context, path string, data map[string][]string) (*Response, error) { return c.readRawWithDataWithContext(ctx, path, data, nil) } func (c *Logical) ParseRawResponseAndCloseBody(resp *Response, err error) (*Secret, error) { if resp != nil { defer resp.Body.Close() } if resp != nil && resp.StatusCode == 404 { secret, parseErr := ParseSecret(resp.Body) switch parseErr { case nil: case io.EOF: return nil, nil default: return nil, parseErr } if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) { return secret, nil } return nil, nil } if err != nil { return nil, err } return ParseSecret(resp.Body) } func (c *Logical) readRawWithDataWithContext(ctx context.Context, path string, values url.Values, extraHeaders http.Header) (*Response, error) { r := c.c.NewRequest(http.MethodGet, "/v1/"+path) if err := c.addExtraHeaders(r, extraHeaders); err != nil { return nil, err } if values != nil { r.Params = maps.Clone(values) } return c.c.RawRequestWithContext(ctx, r) } // ListFromSnapshot lists from the Vault path using a previously loaded // snapshot. The snapshotID parameter is the ID of the loaded snapshot func (c *Logical) ListFromSnapshot(path string, snapshotID string) (*Secret, error) { r := c.c.NewRequest("LIST", "/v1/"+path) r.Params.Set("read_snapshot_id", snapshotID) return c.list(context.Background(), r) } func (c *Logical) List(path string) (*Secret, error) { return c.ListWithContext(context.Background(), path) } func (c *Logical) ListWithContext(ctx context.Context, path string) (*Secret, error) { return c.list(ctx, c.c.NewRequest("LIST", "/v1/"+path)) } func (c *Logical) list(ctx context.Context, r *Request) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() // Set this for broader compatibility, but we use LIST above to be able to // handle the wrapping lookup function r.Method = http.MethodGet r.Params.Set("list", "true") resp, err := c.c.rawRequestWithContext(ctx, r) if resp != nil { defer resp.Body.Close() } if resp != nil && resp.StatusCode == 404 { secret, parseErr := ParseSecret(resp.Body) switch parseErr { case nil: case io.EOF: return nil, nil default: return nil, parseErr } if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) { return secret, nil } return nil, nil } if err != nil { return nil, err } return ParseSecret(resp.Body) } func (c *Logical) Write(path string, data map[string]interface{}) (*Secret, error) { return c.WriteWithContext(context.Background(), path, data) } func (c *Logical) WriteWithContext(ctx context.Context, path string, data map[string]interface{}) (*Secret, error) { r := c.c.NewRequest(http.MethodPut, "/v1/"+path) if err := r.SetJSONBody(data); err != nil { return nil, err } return c.write(ctx, path, r) } func (c *Logical) WriteRaw(path string, data []byte) (*Response, error) { return c.WriteRawWithContext(context.Background(), path, data) } func (c *Logical) WriteRawWithContext(ctx context.Context, path string, data []byte) (*Response, error) { r := c.c.NewRequest(http.MethodPut, "/v1/"+path) r.BodyBytes = data return c.writeRaw(ctx, r) } // WriteWithRequest returns a Secret for the given LogicalRequest. This is a // more flexible version of WriteWithContext, which allows for passing extra // headers to the Vault server. func (c *Logical) WriteWithRequest(ctx context.Context, req LogicalWriteRequest) (*Secret, error) { r := c.c.NewRequest(http.MethodPut, "/v1/"+req.Path()) if err := c.addExtraHeaders(r, req.Headers()); err != nil { return nil, err } if err := r.SetJSONBody(req.Data()); err != nil { return nil, err } return c.write(ctx, req.Path(), r) } // addExtraHeaders adds the given headers to the request, but only if they are // not already set in the request. If a header is already set in the request, it // returns an error for each header that is already set. func (c *Logical) addExtraHeaders(r *Request, headers http.Header) error { var errs error if r == nil { return fmt.Errorf("cannot add extra headers to nil request") } if len(headers) == 0 { return nil } if r.Headers == nil { r.Headers = headers return nil } curHeaders := r.Headers.Clone() for k, v := range headers { ck := http.CanonicalHeaderKey(k) if curVal := curHeaders.Get(ck); curVal != "" { errs = errors.Join(errs, fmt.Errorf("cannot set extra header %q, it is reserved", ck)) continue } curHeaders[ck] = v } if errs != nil { return fmt.Errorf("cannot add extra headers: %w", errs) } r.Headers = curHeaders return nil } // Recover recovers the data at the given Vault path from a loaded snapshot. // The snapshotID parameter is the ID of the loaded snapshot func (c *Logical) Recover(ctx context.Context, path string, snapshotID string) (*Secret, error) { return c.RecoverFromPath(ctx, path, snapshotID, "") } func (c *Logical) RecoverFromPath(ctx context.Context, newPath string, snapshotID string, originalPath string) (*Secret, error) { r := c.c.NewRequest(http.MethodPut, "/v1/"+newPath) r.Params.Set("recover_snapshot_id", snapshotID) r.Headers.Set(SnapshotHeaderName, snapshotID) if originalPath != "" && originalPath != newPath { r.Headers.Set(RecoverSourcePathHeaderName, originalPath) } return c.write(ctx, originalPath, r) } func (c *Logical) JSONMergePatch(ctx context.Context, path string, data map[string]interface{}) (*Secret, error) { r := c.c.NewRequest(http.MethodPatch, "/v1/"+path) r.Headers.Set("Content-Type", "application/merge-patch+json") if err := r.SetJSONBody(data); err != nil { return nil, err } return c.write(ctx, path, r) } func (c *Logical) WriteBytes(path string, data []byte) (*Secret, error) { return c.WriteBytesWithContext(context.Background(), path, data) } func (c *Logical) WriteBytesWithContext(ctx context.Context, path string, data []byte) (*Secret, error) { r := c.c.NewRequest(http.MethodPut, "/v1/"+path) r.BodyBytes = data return c.write(ctx, path, r) } func (c *Logical) write(ctx context.Context, path string, request *Request) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() resp, err := c.c.rawRequestWithContext(ctx, request) if resp != nil { defer resp.Body.Close() } if resp != nil && resp.StatusCode == 404 { secret, parseErr := ParseSecret(resp.Body) switch parseErr { case nil: case io.EOF: return nil, nil default: return nil, parseErr } if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) { return secret, err } } if err != nil { return nil, err } return ParseSecret(resp.Body) } func (c *Logical) writeRaw(ctx context.Context, request *Request) (*Response, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() resp, err := c.c.rawRequestWithContext(ctx, request) return resp, err } func (c *Logical) Delete(path string) (*Secret, error) { return c.DeleteWithContext(context.Background(), path) } func (c *Logical) DeleteWithContext(ctx context.Context, path string) (*Secret, error) { return c.DeleteWithDataWithContext(ctx, path, nil) } func (c *Logical) DeleteWithData(path string, data map[string][]string) (*Secret, error) { return c.DeleteWithDataWithContext(context.Background(), path, data) } // DeleteWithRequest returns a Secret for the given LogicalDeleteRequest. This is a // more flexible version of DeleteWithContext, which allows for passing extra // headers to the Vault server. func (c *Logical) DeleteWithRequest(ctx context.Context, req LogicalDeleteRequest) (*Secret, error) { return c.DeleteWithDataWithContext(ctx, req.Path(), req.Values()) } func (c *Logical) DeleteWithDataWithContext(ctx context.Context, path string, data map[string][]string) (*Secret, error) { return c.deleteWithDataWithContext(ctx, path, data) } func (c *Logical) deleteWithDataWithContext(ctx context.Context, path string, data map[string][]string) (*Secret, error) { return c.delete(ctx, NewDeleteRequest(path, data, nil)) } func (c *Logical) delete(ctx context.Context, req LogicalDeleteRequest) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodDelete, "/v1/"+req.Path()) if values := req.Values(); values != nil { r.Params = values } if err := c.addExtraHeaders(r, req.Headers()); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if resp != nil { defer resp.Body.Close() } if resp != nil && resp.StatusCode == 404 { secret, parseErr := ParseSecret(resp.Body) switch parseErr { case nil: case io.EOF: return nil, nil default: return nil, parseErr } if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) { return secret, err } } if err != nil { return nil, err } return ParseSecret(resp.Body) } func (c *Logical) Unwrap(wrappingToken string) (*Secret, error) { return c.UnwrapWithContext(context.Background(), wrappingToken) } func (c *Logical) UnwrapWithContext(ctx context.Context, wrappingToken string) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() var data map[string]interface{} wt := strings.TrimSpace(wrappingToken) if wrappingToken != "" { if c.c.Token() == "" { c.c.SetToken(wt) } else if wrappingToken != c.c.Token() { data = map[string]interface{}{ "token": wt, } } } r := c.c.NewRequest(http.MethodPut, "/v1/sys/wrapping/unwrap") if err := r.SetJSONBody(data); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if resp != nil { defer resp.Body.Close() } if resp == nil || resp.StatusCode != 404 { if err != nil { return nil, err } if resp == nil { return nil, nil } return ParseSecret(resp.Body) } // In the 404 case this may actually be a wrapped 404 error secret, parseErr := ParseSecret(resp.Body) switch parseErr { case nil: case io.EOF: return nil, nil default: return nil, parseErr } if secret != nil && (len(secret.Warnings) > 0 || len(secret.Data) > 0) { return secret, nil } // Otherwise this might be an old-style wrapping token so attempt the old // method if wrappingToken != "" { origToken := c.c.Token() defer c.c.SetToken(origToken) c.c.SetToken(wrappingToken) } secret, err = c.ReadWithContext(ctx, wrappedResponseLocation) if err != nil { return nil, errwrap.Wrapf(fmt.Sprintf("error reading %q: {{err}}", wrappedResponseLocation), err) } if secret == nil { return nil, fmt.Errorf("no value found at %q", wrappedResponseLocation) } if secret.Data == nil { return nil, fmt.Errorf("\"data\" not found in wrapping response") } if _, ok := secret.Data["response"]; !ok { return nil, fmt.Errorf("\"response\" not found in wrapping response \"data\" map") } wrappedSecret := new(Secret) buf := bytes.NewBufferString(secret.Data["response"].(string)) dec := json.NewDecoder(buf) dec.UseNumber() if err := dec.Decode(wrappedSecret); err != nil { return nil, errwrap.Wrapf("error unmarshalling wrapped secret: {{err}}", err) } return wrappedSecret, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/logical_requests.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "maps" "net/http" "net/url" ) var _ LogicalRequest = (*defaultLogicalRequest)(nil) // NewLogicalReadRequest creates a new LogicalReadRequest with the given path, // values, and headers. func NewLogicalReadRequest(path string, values url.Values, headers http.Header) LogicalReadRequest { return newLogicalRequest(path, values, nil, headers) } // NewLogicalWriteRequest creates a new LogicalWriteRequest with the given path, // data, and headers. func NewLogicalWriteRequest(path string, data map[string]interface{}, headers http.Header) LogicalWriteRequest { return newLogicalRequest(path, nil, data, headers) } // NewDeleteRequest creates a new LogicalDeleteRequest with the given path and values. func NewDeleteRequest(path string, values url.Values, headers http.Header) LogicalDeleteRequest { return newLogicalRequest(path, values, nil, headers) } // newLogicalRequest creates a new LogicalRequest with the given path, values, // data, and headers. func newLogicalRequest(path string, values url.Values, data map[string]interface{}, headers http.Header) LogicalRequest { return &defaultLogicalRequest{ path: path, values: values, data: data, headers: headers, } } // BaseLogicalRequest is the interface for requests to Vault's logical backend // that do not include data or values. type BaseLogicalRequest interface { // Path returns the path to write to in Vault, without the "/v1/" prefix. Path() string // Headers returns the headers to be included in the request to Vault. All // headers are additive, and must not collide with any of the reserved headers. Headers() http.Header } // LogicalRequest is the interface for requests to Vault's logical backend. type LogicalRequest interface { BaseLogicalRequest // Values returns the query parameters to be used in the request. // Values are only used in read and delete requests. Values() url.Values // Data returns the data to be written to the path. It is marshaled to JSON. // Data is only used in write requests. Data() map[string]interface{} } // LogicalWriteRequest is the interface for requests that write data to Vault's // logical backend. type LogicalWriteRequest interface { BaseLogicalRequest Data() map[string]interface{} } // LogicalReadRequest is the interface for requests that read data from Vault's // logical backend. type LogicalReadRequest interface { BaseLogicalRequest Values() url.Values } // LogicalDeleteRequest is the interface for requests that delete data from Vault's // logical backend. It is semantically similar the same as a read request, type LogicalDeleteRequest interface { BaseLogicalRequest Values() url.Values } // defaultLogicalRequest is the default implementation of LogicalRequest. type defaultLogicalRequest struct { path string values url.Values headers http.Header data map[string]interface{} } // Path returns the path to write to in Vault, without the "/v1/" prefix. func (r *defaultLogicalRequest) Path() string { return r.path } // Headers returns a copy of the headers to be included in the request to Vault. func (r *defaultLogicalRequest) Headers() http.Header { if r.headers == nil { return nil } return maps.Clone(r.headers) } // Data returns a copy of the data to be written to the path. func (r *defaultLogicalRequest) Data() map[string]interface{} { if r.data == nil { return nil } return maps.Clone(r.data) } // Values returns a copy of the query parameters to be used in the request. func (r *defaultLogicalRequest) Values() url.Values { if r.values == nil { return nil } return maps.Clone(r.values) } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/output_policy.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "fmt" "net/http" "net/url" "strconv" "strings" ) const ( ErrOutputPolicyRequest = "output a policy, please" ) var LastOutputPolicyError *OutputPolicyError type OutputPolicyError struct { method string path string params url.Values finalHCLString string } func (d *OutputPolicyError) Error() string { if d.finalHCLString == "" { p, err := d.buildSamplePolicy() if err != nil { return err.Error() } d.finalHCLString = p } return ErrOutputPolicyRequest } func (d *OutputPolicyError) HCLString() (string, error) { if d.finalHCLString == "" { p, err := d.buildSamplePolicy() if err != nil { return "", err } d.finalHCLString = p } return d.finalHCLString, nil } // Builds a sample policy document from the request func (d *OutputPolicyError) buildSamplePolicy() (string, error) { operation := d.method // List is often defined as a URL param instead of as an http.Method // this will check for the header and properly switch off of the intended functionality if d.params.Has("list") { isList, err := strconv.ParseBool(d.params.Get("list")) if err != nil { return "", fmt.Errorf("the value of the list url param is not a bool: %v", err) } if isList { operation = "LIST" } } var capabilities []string switch operation { case http.MethodGet, "": capabilities = append(capabilities, "read") case http.MethodPost, http.MethodPut: capabilities = append(capabilities, "create") capabilities = append(capabilities, "update") case http.MethodPatch: capabilities = append(capabilities, "patch") case http.MethodDelete: capabilities = append(capabilities, "delete") case "LIST": capabilities = append(capabilities, "list") } // determine whether to add sudo capability if IsSudoPath(d.path) { capabilities = append(capabilities, "sudo") } return formatOutputPolicy(d.path, capabilities), nil } func formatOutputPolicy(path string, capabilities []string) string { // the OpenAPI response has a / in front of each path, // but policies need the path without that leading slash path = strings.TrimLeft(path, "/") capStr := strings.Join(capabilities, `", "`) return fmt.Sprintf( `path "%s" { capabilities = ["%s"] }`, path, capStr) } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/output_string.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "fmt" "net/http" "strings" "github.com/hashicorp/go-retryablehttp" ) const ( ErrOutputStringRequest = "output a string, please" ) var LastOutputStringError *OutputStringError type OutputStringError struct { *retryablehttp.Request TLSSkipVerify bool ClientCACert, ClientCAPath string ClientCert, ClientKey string finalCurlString string } // Error is here so that we can return this struct as an error from client.rawRequestWithContext(). Note that // the ErrOutputStringRequest constant is never actually used and is completely irrelevant to how this all functions. // We could've just as easily returned an empty string. What matters is the machinery that happens before then where // the curl string is built. So yes, this is confusing, but yes, this is also on purpose, and it is not incorrect. func (d *OutputStringError) Error() string { if d.finalCurlString == "" { cs, err := d.buildCurlString() if err != nil { return err.Error() } d.finalCurlString = cs } return ErrOutputStringRequest } func (d *OutputStringError) CurlString() (string, error) { if d.finalCurlString == "" { cs, err := d.buildCurlString() if err != nil { return "", err } d.finalCurlString = cs } return d.finalCurlString, nil } func (d *OutputStringError) buildCurlString() (string, error) { body, err := d.Request.BodyBytes() if err != nil { return "", err } // Build cURL string finalCurlString := "curl " if d.TLSSkipVerify { finalCurlString += "--insecure " } if d.Request.Method != http.MethodGet { finalCurlString = fmt.Sprintf("%s-X %s ", finalCurlString, d.Request.Method) } if d.ClientCACert != "" { clientCACert := strings.ReplaceAll(d.ClientCACert, "'", "'\"'\"'") finalCurlString = fmt.Sprintf("%s--cacert '%s' ", finalCurlString, clientCACert) } if d.ClientCAPath != "" { clientCAPath := strings.ReplaceAll(d.ClientCAPath, "'", "'\"'\"'") finalCurlString = fmt.Sprintf("%s--capath '%s' ", finalCurlString, clientCAPath) } if d.ClientCert != "" { clientCert := strings.ReplaceAll(d.ClientCert, "'", "'\"'\"'") finalCurlString = fmt.Sprintf("%s--cert '%s' ", finalCurlString, clientCert) } if d.ClientKey != "" { clientKey := strings.ReplaceAll(d.ClientKey, "'", "'\"'\"'") finalCurlString = fmt.Sprintf("%s--key '%s' ", finalCurlString, clientKey) } for k, v := range d.Request.Header { for _, h := range v { if strings.ToLower(k) == "x-vault-token" { h = `$(vault print token)` } finalCurlString = fmt.Sprintf("%s-H \"%s: %s\" ", finalCurlString, k, h) } } if len(body) > 0 { // We need to escape single quotes since that's what we're using to // quote the body escapedBody := strings.ReplaceAll(string(body), "'", "'\"'\"'") finalCurlString = fmt.Sprintf("%s-d '%s' ", finalCurlString, escapedBody) } return fmt.Sprintf("%s%s", finalCurlString, d.Request.URL.String()), nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/plugin_helpers.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "crypto/tls" "crypto/x509" "encoding/base64" "errors" "flag" "net/url" "os" jose "github.com/go-jose/go-jose/v4" "github.com/go-jose/go-jose/v4/jwt" "github.com/hashicorp/errwrap" ) // This file contains helper code used when writing Vault auth method or secrets engine plugins. // // As such, it would be better located in the sdk module with the rest of the code which is only to support plugins, // rather than api, but is here for historical reasons. (The api module used to depend on the sdk module, this code // calls NewClient within the api package, so placing it in the sdk would have created a dependency cycle. This reason // is now historical, as the dependency between sdk and api has since been reversed in direction.) // Moving this code to the sdk would be appropriate if an api v2.0.0 release is ever planned. // // This helper code is used when a plugin is hosted by Vault 1.11 and earlier. Vault 1.12 and sdk v0.6.0 introduced // version 5 of the backend plugin interface, which uses go-plugin's AutoMTLS feature instead of this code. const ( // PluginAutoMTLSEnv is used to ensure AutoMTLS is used. This will override // setting a TLSProviderFunc for a plugin. PluginAutoMTLSEnv = "VAULT_PLUGIN_AUTOMTLS_ENABLED" // PluginMetadataModeEnv is an ENV name used to disable TLS communication // to bootstrap mounting plugins. PluginMetadataModeEnv = "VAULT_PLUGIN_METADATA_MODE" // PluginUnwrapTokenEnv is the ENV name used to pass unwrap tokens to the // plugin. PluginUnwrapTokenEnv = "VAULT_UNWRAP_TOKEN" // CubbyHoleJWTSignatureAlgorithm is the signature algorithm used for // the unwrap token that Vault passes to a plugin when auto-mTLS is // not enabled. CubbyHoleJWTSignatureAlgorithm = jose.ES512 ) // PluginAPIClientMeta is a helper that plugins can use to configure TLS connections // back to Vault. type PluginAPIClientMeta struct { // These are set by the command line flags. flagCACert string flagCAPath string flagClientCert string flagClientKey string flagServerName string flagInsecure bool } // FlagSet returns the flag set for configuring the TLS connection func (f *PluginAPIClientMeta) FlagSet() *flag.FlagSet { fs := flag.NewFlagSet("vault plugin settings", flag.ContinueOnError) fs.StringVar(&f.flagCACert, "ca-cert", "", "") fs.StringVar(&f.flagCAPath, "ca-path", "", "") fs.StringVar(&f.flagClientCert, "client-cert", "", "") fs.StringVar(&f.flagClientKey, "client-key", "", "") fs.StringVar(&f.flagServerName, "tls-server-name", "", "") fs.BoolVar(&f.flagInsecure, "tls-skip-verify", false, "") return fs } // GetTLSConfig will return a TLSConfig based off the values from the flags func (f *PluginAPIClientMeta) GetTLSConfig() *TLSConfig { // If we need custom TLS configuration, then set it if f.flagCACert != "" || f.flagCAPath != "" || f.flagClientCert != "" || f.flagClientKey != "" || f.flagInsecure || f.flagServerName != "" { t := &TLSConfig{ CACert: f.flagCACert, CAPath: f.flagCAPath, ClientCert: f.flagClientCert, ClientKey: f.flagClientKey, TLSServerName: f.flagServerName, Insecure: f.flagInsecure, } return t } return nil } // VaultPluginTLSProvider wraps VaultPluginTLSProviderContext using context.Background. func VaultPluginTLSProvider(apiTLSConfig *TLSConfig) func() (*tls.Config, error) { return VaultPluginTLSProviderContext(context.Background(), apiTLSConfig) } // VaultPluginTLSProviderContext is run inside a plugin and retrieves the response // wrapped TLS certificate from vault. It returns a configured TLS Config. func VaultPluginTLSProviderContext(ctx context.Context, apiTLSConfig *TLSConfig) func() (*tls.Config, error) { if os.Getenv(PluginAutoMTLSEnv) == "true" || os.Getenv(PluginMetadataModeEnv) == "true" { return nil } return func() (*tls.Config, error) { unwrapToken := os.Getenv(PluginUnwrapTokenEnv) parsedJWT, err := jwt.ParseSigned(unwrapToken, []jose.SignatureAlgorithm{CubbyHoleJWTSignatureAlgorithm}) if err != nil { return nil, errwrap.Wrapf("error parsing wrapping token: {{err}}", err) } allClaims := make(map[string]interface{}) if err = parsedJWT.UnsafeClaimsWithoutVerification(&allClaims); err != nil { return nil, errwrap.Wrapf("error parsing claims from wrapping token: {{err}}", err) } addrClaimRaw, ok := allClaims["addr"] if !ok { return nil, errors.New("could not validate addr claim") } vaultAddr, ok := addrClaimRaw.(string) if !ok { return nil, errors.New("could not parse addr claim") } if vaultAddr == "" { return nil, errors.New(`no vault api_addr found`) } // Sanity check the value if _, err := url.Parse(vaultAddr); err != nil { return nil, errwrap.Wrapf("error parsing the vault api_addr: {{err}}", err) } // Unwrap the token clientConf := DefaultConfig() clientConf.Address = vaultAddr if apiTLSConfig != nil { err := clientConf.ConfigureTLS(apiTLSConfig) if err != nil { return nil, errwrap.Wrapf("error configuring api client {{err}}", err) } } client, err := NewClient(clientConf) if err != nil { return nil, errwrap.Wrapf("error during api client creation: {{err}}", err) } // Reset token value to make sure nothing has been set by default client.ClearToken() secret, err := client.Logical().UnwrapWithContext(ctx, unwrapToken) if err != nil { return nil, errwrap.Wrapf("error during token unwrap request: {{err}}", err) } if secret == nil { return nil, errors.New("error during token unwrap request: secret is nil") } // Retrieve and parse the server's certificate serverCertBytesRaw, ok := secret.Data["ServerCert"].(string) if !ok { return nil, errors.New("error unmarshalling certificate") } serverCertBytes, err := base64.StdEncoding.DecodeString(serverCertBytesRaw) if err != nil { return nil, errwrap.Wrapf("error parsing certificate: {{err}}", err) } serverCert, err := x509.ParseCertificate(serverCertBytes) if err != nil { return nil, errwrap.Wrapf("error parsing certificate: {{err}}", err) } // Retrieve and parse the server's private key serverKeyB64, ok := secret.Data["ServerKey"].(string) if !ok { return nil, errors.New("error unmarshalling certificate") } serverKeyRaw, err := base64.StdEncoding.DecodeString(serverKeyB64) if err != nil { return nil, errwrap.Wrapf("error parsing certificate: {{err}}", err) } serverKey, err := x509.ParseECPrivateKey(serverKeyRaw) if err != nil { return nil, errwrap.Wrapf("error parsing certificate: {{err}}", err) } // Add CA cert to the cert pool caCertPool := x509.NewCertPool() caCertPool.AddCert(serverCert) // Build a certificate object out of the server's cert and private key. cert := tls.Certificate{ Certificate: [][]byte{serverCertBytes}, PrivateKey: serverKey, Leaf: serverCert, } // Setup TLS config tlsConfig := &tls.Config{ ClientCAs: caCertPool, RootCAs: caCertPool, ClientAuth: tls.RequireAndVerifyClientCert, // TLS 1.2 minimum MinVersion: tls.VersionTLS12, Certificates: []tls.Certificate{cert}, ServerName: serverCert.Subject.CommonName, } return tlsConfig, nil } } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/plugin_runtime_types.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api // NOTE: this file was copied from // https://github.com/hashicorp/vault/blob/main/sdk/helper/consts/plugin_runtime_types.go // Any changes made should be made to both files at the same time. import "fmt" var PluginRuntimeTypes = _PluginRuntimeTypeValues //go:generate enumer -type=PluginRuntimeType -trimprefix=PluginRuntimeType -transform=snake type PluginRuntimeType uint32 // This is a list of PluginRuntimeTypes used by Vault. const ( PluginRuntimeTypeUnsupported PluginRuntimeType = iota PluginRuntimeTypeContainer ) // ParsePluginRuntimeType is a wrapper around PluginRuntimeTypeString kept for backwards compatibility. func ParsePluginRuntimeType(PluginRuntimeType string) (PluginRuntimeType, error) { t, err := PluginRuntimeTypeString(PluginRuntimeType) if err != nil { return PluginRuntimeTypeUnsupported, fmt.Errorf("%q is not a supported plugin runtime type", PluginRuntimeType) } return t, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/plugin_types.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api // NOTE: this file was copied from // https://github.com/hashicorp/vault/blob/main/sdk/helper/consts/plugin_types.go // Any changes made should be made to both files at the same time. import ( "encoding/json" "fmt" ) var PluginTypes = []PluginType{ PluginTypeUnknown, PluginTypeCredential, PluginTypeDatabase, PluginTypeSecrets, } type PluginType uint32 // This is a list of PluginTypes used by Vault. // If we need to add any in the future, it would // be best to add them to the _end_ of the list below // because they resolve to incrementing numbers, // which may be saved in state somewhere. Thus if // the name for one of those numbers changed because // a value were added to the middle, that could cause // the wrong plugin types to be read from storage // for a given underlying number. Example of the problem // here: https://play.golang.org/p/YAaPw5ww3er const ( PluginTypeUnknown PluginType = iota PluginTypeCredential PluginTypeDatabase PluginTypeSecrets ) func (p PluginType) String() string { switch p { case PluginTypeUnknown: return "unknown" case PluginTypeCredential: return "auth" case PluginTypeDatabase: return "database" case PluginTypeSecrets: return "secret" default: return "unsupported" } } func ParsePluginType(pluginType string) (PluginType, error) { switch pluginType { case "unknown": return PluginTypeUnknown, nil case "auth": return PluginTypeCredential, nil case "database": return PluginTypeDatabase, nil case "secret": return PluginTypeSecrets, nil default: return PluginTypeUnknown, fmt.Errorf("%q is not a supported plugin type", pluginType) } } // UnmarshalJSON implements json.Unmarshaler. It supports unmarshaling either a // string or a uint32. All new serialization will be as a string, but we // previously serialized as a uint32 so we need to support that for backwards // compatibility. func (p *PluginType) UnmarshalJSON(data []byte) error { var asString string err := json.Unmarshal(data, &asString) if err == nil { *p, err = ParsePluginType(asString) return err } var asUint32 uint32 err = json.Unmarshal(data, &asUint32) if err != nil { return err } *p = PluginType(asUint32) switch *p { case PluginTypeUnknown, PluginTypeCredential, PluginTypeDatabase, PluginTypeSecrets: return nil default: return fmt.Errorf("%d is not a supported plugin type", asUint32) } } // MarshalJSON implements json.Marshaler. func (p PluginType) MarshalJSON() ([]byte, error) { return json.Marshal(p.String()) } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/pluginruntimetype_enumer.go ================================================ // Code generated by "enumer -type=PluginRuntimeType -trimprefix=PluginRuntimeType -transform=snake"; DO NOT EDIT. package api import ( "fmt" ) const _PluginRuntimeTypeName = "unsupportedcontainer" var _PluginRuntimeTypeIndex = [...]uint8{0, 11, 20} func (i PluginRuntimeType) String() string { if i >= PluginRuntimeType(len(_PluginRuntimeTypeIndex)-1) { return fmt.Sprintf("PluginRuntimeType(%d)", i) } return _PluginRuntimeTypeName[_PluginRuntimeTypeIndex[i]:_PluginRuntimeTypeIndex[i+1]] } var _PluginRuntimeTypeValues = []PluginRuntimeType{0, 1} var _PluginRuntimeTypeNameToValueMap = map[string]PluginRuntimeType{ _PluginRuntimeTypeName[0:11]: 0, _PluginRuntimeTypeName[11:20]: 1, } // PluginRuntimeTypeString retrieves an enum value from the enum constants string name. // Throws an error if the param is not part of the enum. func PluginRuntimeTypeString(s string) (PluginRuntimeType, error) { if val, ok := _PluginRuntimeTypeNameToValueMap[s]; ok { return val, nil } return 0, fmt.Errorf("%s does not belong to PluginRuntimeType values", s) } // PluginRuntimeTypeValues returns all values of the enum func PluginRuntimeTypeValues() []PluginRuntimeType { return _PluginRuntimeTypeValues } // IsAPluginRuntimeType returns "true" if the value is listed in the enum definition. "false" otherwise func (i PluginRuntimeType) IsAPluginRuntimeType() bool { for _, v := range _PluginRuntimeTypeValues { if i == v { return true } } return false } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/renewbehavior_enumer.go ================================================ // Code generated by "enumer -type=RenewBehavior -trimprefix=RenewBehavior"; DO NOT EDIT. package api import ( "fmt" ) const _RenewBehaviorName = "IgnoreErrorsRenewDisabledErrorOnErrors" var _RenewBehaviorIndex = [...]uint8{0, 12, 25, 38} func (i RenewBehavior) String() string { if i >= RenewBehavior(len(_RenewBehaviorIndex)-1) { return fmt.Sprintf("RenewBehavior(%d)", i) } return _RenewBehaviorName[_RenewBehaviorIndex[i]:_RenewBehaviorIndex[i+1]] } var _RenewBehaviorValues = []RenewBehavior{0, 1, 2} var _RenewBehaviorNameToValueMap = map[string]RenewBehavior{ _RenewBehaviorName[0:12]: 0, _RenewBehaviorName[12:25]: 1, _RenewBehaviorName[25:38]: 2, } // RenewBehaviorString retrieves an enum value from the enum constants string name. // Throws an error if the param is not part of the enum. func RenewBehaviorString(s string) (RenewBehavior, error) { if val, ok := _RenewBehaviorNameToValueMap[s]; ok { return val, nil } return 0, fmt.Errorf("%s does not belong to RenewBehavior values", s) } // RenewBehaviorValues returns all values of the enum func RenewBehaviorValues() []RenewBehavior { return _RenewBehaviorValues } // IsARenewBehavior returns "true" if the value is listed in the enum definition. "false" otherwise func (i RenewBehavior) IsARenewBehavior() bool { for _, v := range _RenewBehaviorValues { if i == v { return true } } return false } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/replication_status.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "encoding/json" "fmt" "net/http" "github.com/mitchellh/mapstructure" ) const ( apiRepPerformanceStatusPath = "/v1/sys/replication/performance/status" apiRepDRStatusPath = "/v1/sys/replication/dr/status" apiRepStatusPath = "/v1/sys/replication/status" ) type ClusterInfo struct { APIAddr string `json:"api_address,omitempty" mapstructure:"api_address"` ClusterAddress string `json:"cluster_address,omitempty" mapstructure:"cluster_address"` ConnectionStatus string `json:"connection_status,omitempty" mapstructure:"connection_status"` LastHeartBeat string `json:"last_heartbeat,omitempty" mapstructure:"last_heartbeat"` LastHeartBeatDurationMillis string `json:"last_heartbeat_duration_ms,omitempty" mapstructure:"last_heartbeat_duration_ms"` ClockSkewMillis string `json:"clock_skew_ms,omitempty" mapstructure:"clock_skew_ms"` NodeID string `json:"node_id,omitempty" mapstructure:"node_id"` ReplicationPrimaryCanaryAgeMillis string `json:"replication_primary_canary_age_ms,omitempty" mapstructure:"replication_primary_canary_age_ms"` } type ReplicationStatusGenericResponse struct { LastDRWAL uint64 `json:"last_dr_wal,omitempty" mapstructure:"last_dr_wal"` LastReindexEpoch string `json:"last_reindex_epoch,omitempty" mapstructure:"last_reindex_epoch"` ClusterID string `json:"cluster_id,omitempty" mapstructure:"cluster_id"` LastWAL uint64 `json:"last_wal,omitempty" mapstructure:"last_wal"` MerkleRoot string `json:"merkle_root,omitempty" mapstructure:"merkle_root"` Mode string `json:"mode,omitempty" mapstructure:"mode"` PrimaryClusterAddr string `json:"primary_cluster_addr,omitempty" mapstructure:"primary_cluster_addr"` LastPerformanceWAL uint64 `json:"last_performance_wal,omitempty" mapstructure:"last_performance_wal"` State string `json:"state,omitempty" mapstructure:"state"` LastRemoteWAL uint64 `json:"last_remote_wal,omitempty" mapstructure:"last_remote_wal"` SecondaryID string `json:"secondary_id,omitempty" mapstructure:"secondary_id"` SSCTGenerationCounter uint64 `json:"ssct_generation_counter,omitempty" mapstructure:"ssct_generation_counter"` KnownSecondaries []string `json:"known_secondaries,omitempty" mapstructure:"known_secondaries"` KnownPrimaryClusterAddrs []string `json:"known_primary_cluster_addrs,omitempty" mapstructure:"known_primary_cluster_addrs"` Primaries []ClusterInfo `json:"primaries,omitempty" mapstructure:"primaries"` Secondaries []ClusterInfo `json:"secondaries,omitempty" mapstructure:"secondaries"` } type ReplicationStatusResponse struct { DR ReplicationStatusGenericResponse `json:"dr,omitempty" mapstructure:"dr"` Performance ReplicationStatusGenericResponse `json:"performance,omitempty" mapstructure:"performance"` } func (c *Sys) ReplicationStatus() (*ReplicationStatusResponse, error) { return c.ReplicationStatusWithContext(context.Background(), apiRepStatusPath) } func (c *Sys) ReplicationPerformanceStatusWithContext(ctx context.Context) (*ReplicationStatusGenericResponse, error) { s, err := c.ReplicationStatusWithContext(ctx, apiRepPerformanceStatusPath) if err != nil { return nil, err } return &s.Performance, nil } func (c *Sys) ReplicationDRStatusWithContext(ctx context.Context) (*ReplicationStatusGenericResponse, error) { s, err := c.ReplicationStatusWithContext(ctx, apiRepDRStatusPath) if err != nil { return nil, err } return &s.DR, nil } func (c *Sys) ReplicationStatusWithContext(ctx context.Context, path string) (*ReplicationStatusResponse, error) { // default to replication/status if path == "" { path = apiRepStatusPath } ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, path) resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer func() { _ = resp.Body.Close() }() // First decode response into a map[string]interface{} data := make(map[string]interface{}) dec := json.NewDecoder(resp.Body) dec.UseNumber() if err := dec.Decode(&data); err != nil { return nil, err } rawData, ok := data["data"] if !ok { return nil, fmt.Errorf("empty data in replication status response") } s := &ReplicationStatusResponse{} g := &ReplicationStatusGenericResponse{} switch { case path == apiRepPerformanceStatusPath: err = mapstructure.Decode(rawData, g) if err != nil { return nil, err } s.Performance = *g case path == apiRepDRStatusPath: err = mapstructure.Decode(rawData, g) if err != nil { return nil, err } s.DR = *g default: err = mapstructure.Decode(rawData, s) if err != nil { return nil, err } return s, err } return s, err } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/request.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "bytes" "encoding/json" "io" "net/http" "net/url" retryablehttp "github.com/hashicorp/go-retryablehttp" ) // Request is a raw request configuration structure used to initiate // API requests to the Vault server. type Request struct { Method string URL *url.URL Host string Params url.Values Headers http.Header ClientToken string MFAHeaderVals []string WrapTTL string Obj interface{} // When possible, use BodyBytes as it is more efficient due to how the // retry logic works BodyBytes []byte // Fallback Body io.Reader BodySize int64 // Whether to request overriding soft-mandatory Sentinel policies (RGPs and // EGPs). If set, the override flag will take effect for all policies // evaluated during the request. PolicyOverride bool // HCPCookie is used to set a http cookie when client is connected to HCP HCPCookie *http.Cookie } // SetJSONBody is used to set a request body that is a JSON-encoded value. func (r *Request) SetJSONBody(val interface{}) error { buf, err := json.Marshal(val) if err != nil { return err } r.Obj = val r.BodyBytes = buf return nil } // ResetJSONBody is used to reset the body for a redirect func (r *Request) ResetJSONBody() error { if r.BodyBytes == nil { return nil } return r.SetJSONBody(r.Obj) } // DEPRECATED: ToHTTP turns this request into a valid *http.Request for use // with the net/http package. func (r *Request) ToHTTP() (*http.Request, error) { req, err := r.toRetryableHTTP() if err != nil { return nil, err } switch { case r.BodyBytes == nil && r.Body == nil: // No body case r.BodyBytes != nil: req.Request.Body = io.NopCloser(bytes.NewReader(r.BodyBytes)) default: if c, ok := r.Body.(io.ReadCloser); ok { req.Request.Body = c } else { req.Request.Body = io.NopCloser(r.Body) } } return req.Request, nil } func (r *Request) toRetryableHTTP() (*retryablehttp.Request, error) { // Encode the query parameters r.URL.RawQuery = r.Params.Encode() // Create the HTTP request, defaulting to retryable var req *retryablehttp.Request var err error var body interface{} switch { case r.BodyBytes == nil && r.Body == nil: // No body case r.BodyBytes != nil: // Use bytes, it's more efficient body = r.BodyBytes default: body = r.Body } req, err = retryablehttp.NewRequest(r.Method, r.URL.RequestURI(), body) if err != nil { return nil, err } req.URL.User = r.URL.User req.URL.Scheme = r.URL.Scheme req.URL.Host = r.URL.Host req.Host = r.Host if r.Headers != nil { for header, vals := range r.Headers { for _, val := range vals { req.Header.Add(header, val) } } } if len(r.ClientToken) != 0 { req.Header.Set(AuthHeaderName, r.ClientToken) } if len(r.WrapTTL) != 0 { req.Header.Set("X-Vault-Wrap-TTL", r.WrapTTL) } if len(r.MFAHeaderVals) != 0 { for _, mfaHeaderVal := range r.MFAHeaderVals { req.Header.Add("X-Vault-MFA", mfaHeaderVal) } } if r.PolicyOverride { req.Header.Set("X-Vault-Policy-Override", "true") } if r.HCPCookie != nil { req.AddCookie(r.HCPCookie) } return req, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/response.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "bytes" "encoding/json" "fmt" "io" "net/http" ) // Response is a raw response that wraps an HTTP response. type Response struct { *http.Response } // DecodeJSON will decode the response body to a JSON structure. This // will consume the response body, but will not close it. Close must // still be called. func (r *Response) DecodeJSON(out interface{}) error { dec := json.NewDecoder(r.Body) dec.UseNumber() return dec.Decode(out) } // Error returns an error response if there is one. If there is an error, // this will fully consume the response body, but will not close it. The // body must still be closed manually. func (r *Response) Error() error { // 200 to 399 are okay status codes. 429 is the code for health status of // standby nodes, otherwise, 429 is treated as quota limit reached. if (r.StatusCode >= 200 && r.StatusCode < 400) || (r.StatusCode == 429 && r.Request.URL.Path == "/v1/sys/health") { return nil } // We have an error. Let's copy the body into our own buffer first, // so that if we can't decode JSON, we can at least copy it raw. bodyBuf := &bytes.Buffer{} if _, err := io.Copy(bodyBuf, r.Body); err != nil { return err } r.Body.Close() r.Body = io.NopCloser(bodyBuf) ns := r.Header.Get(NamespaceHeaderName) // Build up the error object respErr := &ResponseError{ HTTPMethod: r.Request.Method, URL: r.Request.URL.String(), StatusCode: r.StatusCode, NamespacePath: ns, } // Decode the error response if we can. Note that we wrap the bodyBuf // in a bytes.Reader here so that the JSON decoder doesn't move the // read pointer for the original buffer. var resp ErrorResponse dec := json.NewDecoder(bytes.NewReader(bodyBuf.Bytes())) dec.UseNumber() if err := dec.Decode(&resp); err != nil { // Store the fact that we couldn't decode the errors respErr.RawError = true respErr.Errors = []string{bodyBuf.String()} } else { // Store the decoded errors respErr.Errors = resp.Errors } return respErr } // ErrorResponse is the raw structure of errors when they're returned by the // HTTP API. type ErrorResponse struct { Errors []string } // ResponseError is the error returned when Vault responds with an error or // non-success HTTP status code. If a request to Vault fails because of a // network error a different error message will be returned. ResponseError gives // access to the underlying errors and status code. type ResponseError struct { // HTTPMethod is the HTTP method for the request (PUT, GET, etc). HTTPMethod string // URL is the URL of the request. URL string // StatusCode is the HTTP status code. StatusCode int // RawError marks that the underlying error messages returned by Vault were // not parsable. The Errors slice will contain the raw response body as the // first and only error string if this value is set to true. RawError bool // Errors are the underlying errors returned by Vault. Errors []string // Namespace path to be reported to the client if it is set to anything other // than root NamespacePath string } // Error returns a human-readable error string for the response error. func (r *ResponseError) Error() string { errString := "Errors" if r.RawError { errString = "Raw Message" } var ns string if r.NamespacePath != "" && r.NamespacePath != "root/" { ns = "Namespace: " + r.NamespacePath + "\n" } var errBody bytes.Buffer errBody.WriteString(fmt.Sprintf( "Error making API request.\n\n"+ ns+ "URL: %s %s\n"+ "Code: %d. %s:\n\n", r.HTTPMethod, r.URL, r.StatusCode, errString)) if r.RawError && len(r.Errors) == 1 { errBody.WriteString(r.Errors[0]) } else { for _, err := range r.Errors { errBody.WriteString(fmt.Sprintf("* %s", err)) } } return errBody.String() } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/secret.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "bytes" "encoding/json" "errors" "fmt" "io" "reflect" "strings" "time" "github.com/hashicorp/errwrap" "github.com/hashicorp/go-secure-stdlib/parseutil" ) // Secret is the structure returned for every secret within Vault. type Secret struct { // The request ID that generated this response RequestID string `json:"request_id"` LeaseID string `json:"lease_id"` LeaseDuration int `json:"lease_duration"` Renewable bool `json:"renewable"` // Data is the actual contents of the secret. The format of the data // is arbitrary and up to the secret backend. Data map[string]interface{} `json:"data"` // Warnings contains any warnings related to the operation. These // are not issues that caused the command to fail, but that the // client should be aware of. Warnings []string `json:"warnings"` // Auth, if non-nil, means that there was authentication information // attached to this response. Auth *SecretAuth `json:"auth,omitempty"` // WrapInfo, if non-nil, means that the initial response was wrapped in the // cubbyhole of the given token (which has a TTL of the given number of // seconds) WrapInfo *SecretWrapInfo `json:"wrap_info,omitempty"` // MountType, if non-empty, provides some information about what kind // of mount this secret came from. MountType string `json:"mount_type,omitempty"` } // TokenID returns the standardized token ID (token) for the given secret. func (s *Secret) TokenID() (string, error) { if s == nil { return "", nil } if s.Auth != nil && len(s.Auth.ClientToken) > 0 { return s.Auth.ClientToken, nil } if s.Data == nil || s.Data["id"] == nil { return "", nil } id, ok := s.Data["id"].(string) if !ok { return "", fmt.Errorf("token found but in the wrong format") } return id, nil } // TokenAccessor returns the standardized token accessor for the given secret. // If the secret is nil or does not contain an accessor, this returns the empty // string. func (s *Secret) TokenAccessor() (string, error) { if s == nil { return "", nil } if s.Auth != nil && len(s.Auth.Accessor) > 0 { return s.Auth.Accessor, nil } if s.Data == nil || s.Data["accessor"] == nil { return "", nil } accessor, ok := s.Data["accessor"].(string) if !ok { return "", fmt.Errorf("token found but in the wrong format") } return accessor, nil } // TokenRemainingUses returns the standardized remaining uses for the given // secret. If the secret is nil or does not contain the "num_uses", this // returns -1. On error, this will return -1 and a non-nil error. func (s *Secret) TokenRemainingUses() (int, error) { if s == nil || s.Data == nil || s.Data["num_uses"] == nil { return -1, nil } return parseutil.SafeParseInt(s.Data["num_uses"]) } // TokenPolicies returns the standardized list of policies for the given secret. // If the secret is nil or does not contain any policies, this returns nil. It // also populates the secret's Auth info with identity/token policy info. func (s *Secret) TokenPolicies() ([]string, error) { if s == nil { return nil, nil } if s.Auth != nil && len(s.Auth.Policies) > 0 { return s.Auth.Policies, nil } if s.Data == nil || s.Data["policies"] == nil { return nil, nil } var tokenPolicies []string // Token policies { _, ok := s.Data["policies"] if !ok { goto TOKEN_DONE } sList, ok := s.Data["policies"].([]string) if ok { tokenPolicies = sList goto TOKEN_DONE } list, ok := s.Data["policies"].([]interface{}) if !ok { return nil, fmt.Errorf("unable to convert token policies to expected format") } for _, v := range list { p, ok := v.(string) if !ok { return nil, fmt.Errorf("unable to convert policy %v to string", v) } tokenPolicies = append(tokenPolicies, p) } } TOKEN_DONE: var identityPolicies []string // Identity policies { v, ok := s.Data["identity_policies"] if !ok || v == nil { goto DONE } if s.Data["identity_policies"] == nil { goto DONE } sList, ok := s.Data["identity_policies"].([]string) if ok { identityPolicies = sList goto DONE } list, ok := s.Data["identity_policies"].([]interface{}) if !ok { return nil, fmt.Errorf("unable to convert identity policies to expected format") } for _, v := range list { p, ok := v.(string) if !ok { return nil, fmt.Errorf("unable to convert policy %v to string", v) } identityPolicies = append(identityPolicies, p) } } DONE: if s.Auth == nil { s.Auth = &SecretAuth{} } policies := append(tokenPolicies, identityPolicies...) s.Auth.TokenPolicies = tokenPolicies s.Auth.IdentityPolicies = identityPolicies s.Auth.Policies = policies return policies, nil } // TokenMetadata returns the map of metadata associated with this token, if any // exists. If the secret is nil or does not contain the "metadata" key, this // returns nil. func (s *Secret) TokenMetadata() (map[string]string, error) { if s == nil { return nil, nil } if s.Auth != nil && len(s.Auth.Metadata) > 0 { return s.Auth.Metadata, nil } if s.Data == nil || (s.Data["metadata"] == nil && s.Data["meta"] == nil) { return nil, nil } data, ok := s.Data["metadata"].(map[string]interface{}) if !ok { data, ok = s.Data["meta"].(map[string]interface{}) if !ok { return nil, fmt.Errorf("unable to convert metadata field to expected format") } } metadata := make(map[string]string, len(data)) for k, v := range data { typed, ok := v.(string) if !ok { return nil, fmt.Errorf("unable to convert metadata value %v to string", v) } metadata[k] = typed } return metadata, nil } // TokenIsRenewable returns the standardized token renewability for the given // secret. If the secret is nil or does not contain the "renewable" key, this // returns false. func (s *Secret) TokenIsRenewable() (bool, error) { if s == nil { return false, nil } if s.Auth != nil && s.Auth.Renewable { return s.Auth.Renewable, nil } if s.Data == nil || s.Data["renewable"] == nil { return false, nil } renewable, err := parseutil.ParseBool(s.Data["renewable"]) if err != nil { return false, errwrap.Wrapf("could not convert renewable value to a boolean: {{err}}", err) } return renewable, nil } // TokenTTL returns the standardized remaining token TTL for the given secret. // If the secret is nil or does not contain a TTL, this returns 0. func (s *Secret) TokenTTL() (time.Duration, error) { if s == nil { return 0, nil } if s.Auth != nil && s.Auth.LeaseDuration > 0 { return time.Duration(s.Auth.LeaseDuration) * time.Second, nil } if s.Data == nil || s.Data["ttl"] == nil { return 0, nil } ttl, err := parseutil.ParseDurationSecond(s.Data["ttl"]) if err != nil { return 0, err } return ttl, nil } // SecretWrapInfo contains wrapping information if we have it. If what is // contained is an authentication token, the accessor for the token will be // available in WrappedAccessor. type SecretWrapInfo struct { Token string `json:"token"` Accessor string `json:"accessor"` TTL int `json:"ttl"` CreationTime time.Time `json:"creation_time"` CreationPath string `json:"creation_path"` WrappedAccessor string `json:"wrapped_accessor"` } type MFAMethodID struct { Type string `json:"type,omitempty"` ID string `json:"id,omitempty"` UsesPasscode bool `json:"uses_passcode,omitempty"` Name string `json:"name,omitempty"` // SelfEnrollmentEnabled indicates whether the user does not yet have an MFA // secret for this method and self-enrollment is enabled for it. Clients (like the UI) can use // this to determine whether to offer the user a way to generate an MFA secret // for this method. SelfEnrollmentEnabled bool `json:"self_enrollment_enabled,omitempty"` } type MFAConstraintAny struct { Any []*MFAMethodID `json:"any,omitempty"` } type MFARequirement struct { MFARequestID string `json:"mfa_request_id,omitempty"` MFAConstraints map[string]*MFAConstraintAny `json:"mfa_constraints,omitempty"` } // SecretAuth is the structure containing auth information if we have it. type SecretAuth struct { ClientToken string `json:"client_token"` Accessor string `json:"accessor"` Policies []string `json:"policies"` TokenPolicies []string `json:"token_policies"` IdentityPolicies []string `json:"identity_policies"` Metadata map[string]string `json:"metadata"` Orphan bool `json:"orphan"` EntityID string `json:"entity_id"` LeaseDuration int `json:"lease_duration"` Renewable bool `json:"renewable"` MFARequirement *MFARequirement `json:"mfa_requirement"` } // ParseSecret is used to parse a secret value from JSON from an io.Reader. func ParseSecret(r io.Reader) (*Secret, error) { // First read the data into a buffer. Not super efficient but we want to // know if we actually have a body or not. var buf bytes.Buffer // io.Reader is treated like a stream and cannot be read // multiple times. Duplicating this stream using TeeReader // to use this data in case there is no top-level data from // api response var teebuf bytes.Buffer tee := io.TeeReader(r, &teebuf) _, err := buf.ReadFrom(tee) if err != nil { return nil, err } if buf.Len() == 0 { return nil, nil } // First decode the JSON into a map[string]interface{} var secret Secret dec := json.NewDecoder(&buf) dec.UseNumber() if err := dec.Decode(&secret); err != nil { return nil, err } // If the secret is null, add raw data to secret data if present if reflect.DeepEqual(secret, Secret{}) { data := make(map[string]interface{}) dec := json.NewDecoder(&teebuf) dec.UseNumber() if err := dec.Decode(&data); err != nil { return nil, err } errRaw, errPresent := data["errors"] // if only errors are present in the resp.Body return nil // to return value not found as it does not have any raw data if len(data) == 1 && errPresent { return nil, nil } // if errors are present along with raw data return the error if errPresent { var errStrArray []string errBytes, err := json.Marshal(errRaw) if err != nil { return nil, err } if err := json.Unmarshal(errBytes, &errStrArray); err != nil { return nil, err } return nil, errors.New(strings.Join(errStrArray, " ")) } // if any raw data is present in resp.Body, add it to secret if len(data) > 0 { secret.Data = data } } return &secret, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/ssh.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "fmt" "net/http" ) // SSH is used to return a client to invoke operations on SSH backend. type SSH struct { c *Client MountPoint string } // SSH returns the client for logical-backend API calls. func (c *Client) SSH() *SSH { return c.SSHWithMountPoint(SSHHelperDefaultMountPoint) } // SSHWithMountPoint returns the client with specific SSH mount point. func (c *Client) SSHWithMountPoint(mountPoint string) *SSH { return &SSH{ c: c, MountPoint: mountPoint, } } // Credential wraps CredentialWithContext using context.Background. func (c *SSH) Credential(role string, data map[string]interface{}) (*Secret, error) { return c.CredentialWithContext(context.Background(), role, data) } // CredentialWithContext invokes the SSH backend API to create a credential to establish an SSH session. func (c *SSH) CredentialWithContext(ctx context.Context, role string, data map[string]interface{}) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPut, fmt.Sprintf("/v1/%s/creds/%s", c.MountPoint, role)) if err := r.SetJSONBody(data); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() return ParseSecret(resp.Body) } // SignKey wraps SignKeyWithContext using context.Background. func (c *SSH) SignKey(role string, data map[string]interface{}) (*Secret, error) { return c.SignKeyWithContext(context.Background(), role, data) } // SignKeyWithContext signs the given public key and returns a signed public key to pass // along with the SSH request. func (c *SSH) SignKeyWithContext(ctx context.Context, role string, data map[string]interface{}) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPut, fmt.Sprintf("/v1/%s/sign/%s", c.MountPoint, role)) if err := r.SetJSONBody(data); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() return ParseSecret(resp.Body) } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/ssh_agent.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "crypto/tls" "crypto/x509" "fmt" "io/ioutil" "net/http" "os" "github.com/hashicorp/errwrap" cleanhttp "github.com/hashicorp/go-cleanhttp" multierror "github.com/hashicorp/go-multierror" rootcerts "github.com/hashicorp/go-rootcerts" "github.com/hashicorp/hcl" "github.com/hashicorp/hcl/hcl/ast" "github.com/mitchellh/mapstructure" ) const ( // SSHHelperDefaultMountPoint is the default path at which SSH backend will be // mounted in the Vault server. SSHHelperDefaultMountPoint = "ssh" // VerifyEchoRequest is the echo request message sent as OTP by the helper. VerifyEchoRequest = "verify-echo-request" // VerifyEchoResponse is the echo response message sent as a response to OTP // matching echo request. VerifyEchoResponse = "verify-echo-response" ) // SSHHelper is a structure representing a vault-ssh-helper which can talk to vault server // in order to verify the OTP entered by the user. It contains the path at which // SSH backend is mounted at the server. type SSHHelper struct { c *Client MountPoint string } // SSHVerifyResponse is a structure representing the fields in Vault server's // response. type SSHVerifyResponse struct { // Usually empty. If the request OTP is echo request message, this will // be set to the corresponding echo response message. Message string `json:"message" mapstructure:"message"` // Username associated with the OTP Username string `json:"username" mapstructure:"username"` // IP associated with the OTP IP string `json:"ip" mapstructure:"ip"` // Name of the role against which the OTP was issued RoleName string `json:"role_name" mapstructure:"role_name"` } // SSHHelperConfig is a structure which represents the entries from the vault-ssh-helper's configuration file. type SSHHelperConfig struct { VaultAddr string `hcl:"vault_addr"` SSHMountPoint string `hcl:"ssh_mount_point"` Namespace string `hcl:"namespace"` CACert string `hcl:"ca_cert"` CAPath string `hcl:"ca_path"` AllowedCidrList string `hcl:"allowed_cidr_list"` AllowedRoles string `hcl:"allowed_roles"` TLSSkipVerify bool `hcl:"tls_skip_verify"` TLSServerName string `hcl:"tls_server_name"` } // SetTLSParameters sets the TLS parameters for this SSH agent. func (c *SSHHelperConfig) SetTLSParameters(clientConfig *Config, certPool *x509.CertPool) { tlsConfig := &tls.Config{ InsecureSkipVerify: c.TLSSkipVerify, MinVersion: tls.VersionTLS12, RootCAs: certPool, ServerName: c.TLSServerName, } transport := cleanhttp.DefaultTransport() transport.TLSClientConfig = tlsConfig clientConfig.HttpClient.Transport = transport } // Returns true if any of the following conditions are true: // - CA cert is configured // - CA path is configured // - configured to skip certificate verification // - TLS server name is configured func (c *SSHHelperConfig) shouldSetTLSParameters() bool { return c.CACert != "" || c.CAPath != "" || c.TLSServerName != "" || c.TLSSkipVerify } // NewClient returns a new client for the configuration. This client will be used by the // vault-ssh-helper to communicate with Vault server and verify the OTP entered by user. // If the configuration supplies Vault SSL certificates, then the client will // have TLS configured in its transport. func (c *SSHHelperConfig) NewClient() (*Client, error) { // Creating a default client configuration for communicating with vault server. clientConfig := DefaultConfig() // Pointing the client to the actual address of vault server. clientConfig.Address = c.VaultAddr // Check if certificates are provided via config file. if c.shouldSetTLSParameters() { rootConfig := &rootcerts.Config{ CAFile: c.CACert, CAPath: c.CAPath, } certPool, err := rootcerts.LoadCACerts(rootConfig) if err != nil { return nil, err } // Enable TLS on the HTTP client information c.SetTLSParameters(clientConfig, certPool) } // Creating the client object for the given configuration client, err := NewClient(clientConfig) if err != nil { return nil, err } // Configure namespace if c.Namespace != "" { client.SetNamespace(c.Namespace) } return client, nil } // LoadSSHHelperConfig loads ssh-helper's configuration from the file and populates the corresponding // in-memory structure. // // Vault address is a required parameter. // Mount point defaults to "ssh". func LoadSSHHelperConfig(path string) (*SSHHelperConfig, error) { contents, err := ioutil.ReadFile(path) if err != nil && !os.IsNotExist(err) { return nil, multierror.Prefix(err, "ssh_helper:") } return ParseSSHHelperConfig(string(contents)) } // ParseSSHHelperConfig parses the given contents as a string for the SSHHelper // configuration. func ParseSSHHelperConfig(contents string) (*SSHHelperConfig, error) { // TODO (HCL_DUP_KEYS_DEPRECATION): replace with simple call to hcl.Parse once deprecation of duplicate attributes // is over, for now just ignore duplicates root, _, err := parseAndCheckForDuplicateHclAttributes(contents) if err != nil { return nil, errwrap.Wrapf("error parsing config: {{err}}", err) } list, ok := root.Node.(*ast.ObjectList) if !ok { return nil, fmt.Errorf("error parsing config: file doesn't contain a root object") } valid := []string{ "vault_addr", "ssh_mount_point", "namespace", "ca_cert", "ca_path", "allowed_cidr_list", "allowed_roles", "tls_skip_verify", "tls_server_name", } if err := CheckHCLKeys(list, valid); err != nil { return nil, multierror.Prefix(err, "ssh_helper:") } var c SSHHelperConfig c.SSHMountPoint = SSHHelperDefaultMountPoint if err := hcl.DecodeObject(&c, list); err != nil { return nil, multierror.Prefix(err, "ssh_helper:") } if c.VaultAddr == "" { return nil, fmt.Errorf(`missing config "vault_addr"`) } return &c, nil } func CheckHCLKeys(node ast.Node, valid []string) error { var list *ast.ObjectList switch n := node.(type) { case *ast.ObjectList: list = n case *ast.ObjectType: list = n.List default: return fmt.Errorf("cannot check HCL keys of type %T", n) } validMap := make(map[string]struct{}, len(valid)) for _, v := range valid { validMap[v] = struct{}{} } var result error for _, item := range list.Items { key := item.Keys[0].Token.Value().(string) if _, ok := validMap[key]; !ok { result = multierror.Append(result, fmt.Errorf("invalid key %q on line %d", key, item.Assign.Line)) } } return result } // SSHHelper creates an SSHHelper object which can talk to Vault server with SSH backend // mounted at default path ("ssh"). func (c *Client) SSHHelper() *SSHHelper { return c.SSHHelperWithMountPoint(SSHHelperDefaultMountPoint) } // SSHHelperWithMountPoint creates an SSHHelper object which can talk to Vault server with SSH backend // mounted at a specific mount point. func (c *Client) SSHHelperWithMountPoint(mountPoint string) *SSHHelper { return &SSHHelper{ c: c, MountPoint: mountPoint, } } // Verify verifies if the key provided by user is present in Vault server. The response // will contain the IP address and username associated with the OTP. In case the // OTP matches the echo request message, instead of searching an entry for the OTP, // an echo response message is returned. This feature is used by ssh-helper to verify if // its configured correctly. func (c *SSHHelper) Verify(otp string) (*SSHVerifyResponse, error) { return c.VerifyWithContext(context.Background(), otp) } // VerifyWithContext the same as Verify but with a custom context. func (c *SSHHelper) VerifyWithContext(ctx context.Context, otp string) (*SSHVerifyResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() data := map[string]interface{}{ "otp": otp, } verifyPath := fmt.Sprintf("/v1/%s/verify", c.MountPoint) r := c.c.NewRequest(http.MethodPut, verifyPath) if err := r.SetJSONBody(data); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret.Data == nil { return nil, nil } var verifyResp SSHVerifyResponse err = mapstructure.Decode(secret.Data, &verifyResp) if err != nil { return nil, err } return &verifyResp, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sudo_paths.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "regexp" ) // sudoPaths is a map containing the paths that require a token's policy // to have the "sudo" capability. The keys are the paths as strings, in // the same format as they are returned by the OpenAPI spec. The values // are the regular expressions that can be used to test whether a given // path matches that path or not (useful specifically for the paths that // contain templated fields.) var sudoPaths = map[string]*regexp.Regexp{ "/auth/token/accessors": regexp.MustCompile(`^/auth/token/accessors/?$`), "/auth/token/revoke-orphan": regexp.MustCompile(`^/auth/token/revoke-orphan$`), "/pki/root": regexp.MustCompile(`^/pki/root$`), "/pki/root/sign-self-issued": regexp.MustCompile(`^/pki/root/sign-self-issued$`), "/sys/audit": regexp.MustCompile(`^/sys/audit$`), "/sys/audit/{path}": regexp.MustCompile(`^/sys/audit/.+$`), "/sys/auth/{path}": regexp.MustCompile(`^/sys/auth/.+$`), "/sys/auth/{path}/tune": regexp.MustCompile(`^/sys/auth/.+/tune$`), "/sys/config/auditing/request-headers": regexp.MustCompile(`^/sys/config/auditing/request-headers$`), "/sys/config/auditing/request-headers/{header}": regexp.MustCompile(`^/sys/config/auditing/request-headers/.+$`), "/sys/config/cors": regexp.MustCompile(`^/sys/config/cors$`), "/sys/config/ui/headers": regexp.MustCompile(`^/sys/config/ui/headers/?$`), "/sys/config/ui/headers/{header}": regexp.MustCompile(`^/sys/config/ui/headers/.+$`), "/sys/internal/inspect/router/{tag}": regexp.MustCompile(`^/sys/internal/inspect/router/.+$`), "/sys/internal/counters/activity/export": regexp.MustCompile(`^/sys/internal/counters/activity/export$`), "/sys/leases": regexp.MustCompile(`^/sys/leases$`), // This entry is a bit wrong... sys/leases/lookup does NOT require sudo. But sys/leases/lookup/ with a trailing // slash DOES require sudo. But the part of the Vault CLI that uses this logic doesn't pass operation-appropriate // trailing slashes, it always strips them off, so we end up giving the wrong answer for one of these. "/sys/leases/lookup/{prefix}": regexp.MustCompile(`^/sys/leases/lookup(?:/.+)?$`), "/sys/leases/revoke-force/{prefix}": regexp.MustCompile(`^/sys/leases/revoke-force/.+$`), "/sys/leases/revoke-prefix/{prefix}": regexp.MustCompile(`^/sys/leases/revoke-prefix/.+$`), "/sys/plugins/catalog/{name}": regexp.MustCompile(`^/sys/plugins/catalog/[^/]+$`), "/sys/plugins/catalog/{type}": regexp.MustCompile(`^/sys/plugins/catalog/[\w-]+$`), "/sys/plugins/catalog/{type}/{name}": regexp.MustCompile(`^/sys/plugins/catalog/[\w-]+/[^/]+$`), "/sys/plugins/runtimes/catalog": regexp.MustCompile(`^/sys/plugins/runtimes/catalog/?$`), "/sys/plugins/runtimes/catalog/{type}/{name}": regexp.MustCompile(`^/sys/plugins/runtimes/catalog/[\w-]+/[^/]+$`), "/sys/raw/{path}": regexp.MustCompile(`^/sys/raw(?:/.+)?$`), "/sys/remount": regexp.MustCompile(`^/sys/remount$`), "/sys/revoke-force/{prefix}": regexp.MustCompile(`^/sys/revoke-force/.+$`), "/sys/revoke-prefix/{prefix}": regexp.MustCompile(`^/sys/revoke-prefix/.+$`), "/sys/rotate": regexp.MustCompile(`^/sys/rotate$`), "/sys/seal": regexp.MustCompile(`^/sys/seal$`), "/sys/step-down": regexp.MustCompile(`^/sys/step-down$`), // enterprise-only paths "/sys/replication/dr/primary/secondary-token": regexp.MustCompile(`^/sys/replication/dr/primary/secondary-token$`), "/sys/replication/performance/primary/secondary-token": regexp.MustCompile(`^/sys/replication/performance/primary/secondary-token$`), "/sys/replication/primary/secondary-token": regexp.MustCompile(`^/sys/replication/primary/secondary-token$`), "/sys/replication/reindex": regexp.MustCompile(`^/sys/replication/reindex$`), "/sys/storage/raft/snapshot-auto/config": regexp.MustCompile(`^/sys/storage/raft/snapshot-auto/config/?$`), "/sys/storage/raft/snapshot-auto/config/{name}": regexp.MustCompile(`^/sys/storage/raft/snapshot-auto/config/[^/]+$`), } func SudoPaths() map[string]*regexp.Regexp { return sudoPaths } // Determine whether the given path requires the sudo capability. // Note that this uses hardcoded static path information, so will return incorrect results for paths in namespaces, // or for secret engines mounted at non-default paths. // Expects to receive a path with an initial slash, but no trailing slashes, as the Vault CLI (the only known and // expected user of this function) sanitizes its paths that way. func IsSudoPath(path string) bool { // Return early if the path is any of the non-templated sudo paths. if _, ok := sudoPaths[path]; ok { return true } // Some sudo paths have templated fields in them. // (e.g. /sys/revoke-prefix/{prefix}) // The values in the sudoPaths map are actually regular expressions, // so we can check if our path matches against them. for _, sudoPathRegexp := range sudoPaths { match := sudoPathRegexp.MatchString(path) if match { return true } } return false } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api // Sys is used to perform system-related operations on Vault. type Sys struct { c *Client } // Sys is used to return the client for sys-related API calls. func (c *Client) Sys() *Sys { return &Sys{c: c} } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_audit.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "errors" "fmt" "net/http" "github.com/mitchellh/mapstructure" ) func (c *Sys) AuditHash(path string, input string) (string, error) { return c.AuditHashWithContext(context.Background(), path, input) } func (c *Sys) AuditHashWithContext(ctx context.Context, path string, input string) (string, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() body := map[string]interface{}{ "input": input, } r := c.c.NewRequest(http.MethodPut, fmt.Sprintf("/v1/sys/audit-hash/%s", path)) if err := r.SetJSONBody(body); err != nil { return "", err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return "", err } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return "", err } if secret == nil || secret.Data == nil { return "", errors.New("data from server response is empty") } hash, ok := secret.Data["hash"] if !ok { return "", errors.New("hash not found in response data") } hashStr, ok := hash.(string) if !ok { return "", errors.New("could not parse hash in response data") } return hashStr, nil } func (c *Sys) ListAudit() (map[string]*Audit, error) { return c.ListAuditWithContext(context.Background()) } func (c *Sys) ListAuditWithContext(ctx context.Context) (map[string]*Audit, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, "/v1/sys/audit") resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } mounts := map[string]*Audit{} err = mapstructure.Decode(secret.Data, &mounts) if err != nil { return nil, err } return mounts, nil } // DEPRECATED: Use EnableAuditWithOptions instead func (c *Sys) EnableAudit( path string, auditType string, desc string, opts map[string]string, ) error { return c.EnableAuditWithOptions(path, &EnableAuditOptions{ Type: auditType, Description: desc, Options: opts, }) } func (c *Sys) EnableAuditWithOptions(path string, options *EnableAuditOptions) error { return c.EnableAuditWithOptionsWithContext(context.Background(), path, options) } func (c *Sys) EnableAuditWithOptionsWithContext(ctx context.Context, path string, options *EnableAuditOptions) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPut, fmt.Sprintf("/v1/sys/audit/%s", path)) if err := r.SetJSONBody(options); err != nil { return err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return err } defer resp.Body.Close() return nil } func (c *Sys) DisableAudit(path string) error { return c.DisableAuditWithContext(context.Background(), path) } func (c *Sys) DisableAuditWithContext(ctx context.Context, path string) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodDelete, fmt.Sprintf("/v1/sys/audit/%s", path)) resp, err := c.c.rawRequestWithContext(ctx, r) if err == nil { defer resp.Body.Close() } return err } // Structures for the requests/response are all down here. They aren't // individually documented because the map almost directly to the raw HTTP API // documentation. Please refer to that documentation for more details. type EnableAuditOptions struct { Type string `json:"type" mapstructure:"type"` Description string `json:"description" mapstructure:"description"` Options map[string]string `json:"options" mapstructure:"options"` Local bool `json:"local" mapstructure:"local"` } type Audit struct { Type string `json:"type" mapstructure:"type"` Description string `json:"description" mapstructure:"description"` Options map[string]string `json:"options" mapstructure:"options"` Local bool `json:"local" mapstructure:"local"` Path string `json:"path" mapstructure:"path"` } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_auth.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "errors" "fmt" "net/http" "github.com/mitchellh/mapstructure" ) func (c *Sys) GetAuth(path string) (*AuthMount, error) { return c.GetAuthWithContext(context.Background(), path) } func (c *Sys) GetAuthWithContext(ctx context.Context, path string) (*AuthMount, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() // use `sys/mounts/auth/:path` so we don't require sudo permissions // historically, `sys/auth` doesn't require sudo, so we don't require it here either r := c.c.NewRequest(http.MethodGet, fmt.Sprintf("/v1/sys/mounts/auth/%s", path)) resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } mount := AuthMount{} err = mapstructure.Decode(secret.Data, &mount) if err != nil { return nil, err } return &mount, nil } func (c *Sys) ListAuth() (map[string]*AuthMount, error) { return c.ListAuthWithContext(context.Background()) } func (c *Sys) ListAuthWithContext(ctx context.Context) (map[string]*AuthMount, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, "/v1/sys/auth") resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } mounts := map[string]*AuthMount{} err = mapstructure.Decode(secret.Data, &mounts) if err != nil { return nil, err } return mounts, nil } // DEPRECATED: Use EnableAuthWithOptions instead func (c *Sys) EnableAuth(path, authType, desc string) error { return c.EnableAuthWithOptions(path, &EnableAuthOptions{ Type: authType, Description: desc, }) } func (c *Sys) EnableAuthWithOptions(path string, options *EnableAuthOptions) error { return c.EnableAuthWithOptionsWithContext(context.Background(), path, options) } func (c *Sys) EnableAuthWithOptionsWithContext(ctx context.Context, path string, options *EnableAuthOptions) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPost, fmt.Sprintf("/v1/sys/auth/%s", path)) if err := r.SetJSONBody(options); err != nil { return err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return err } defer resp.Body.Close() return nil } func (c *Sys) DisableAuth(path string) error { return c.DisableAuthWithContext(context.Background(), path) } func (c *Sys) DisableAuthWithContext(ctx context.Context, path string) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodDelete, fmt.Sprintf("/v1/sys/auth/%s", path)) resp, err := c.c.rawRequestWithContext(ctx, r) if err == nil { defer resp.Body.Close() } return err } // Rather than duplicate, we can use modern Go's type aliasing type ( EnableAuthOptions = MountInput AuthConfigInput = MountConfigInput AuthMount = MountOutput AuthConfigOutput = MountConfigOutput ) ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_capabilities.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "errors" "fmt" "net/http" "github.com/mitchellh/mapstructure" ) func (c *Sys) CapabilitiesSelf(path string) ([]string, error) { return c.CapabilitiesSelfWithContext(context.Background(), path) } func (c *Sys) CapabilitiesSelfWithContext(ctx context.Context, path string) ([]string, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() return c.CapabilitiesWithContext(ctx, c.c.Token(), path) } func (c *Sys) Capabilities(token, path string) ([]string, error) { return c.CapabilitiesWithContext(context.Background(), token, path) } func (c *Sys) CapabilitiesWithContext(ctx context.Context, token, path string) ([]string, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() body := map[string]string{ "token": token, "path": path, } reqPath := "/v1/sys/capabilities" if token == c.c.Token() { reqPath = fmt.Sprintf("%s-self", reqPath) } r := c.c.NewRequest(http.MethodPost, reqPath) if err := r.SetJSONBody(body); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } var res []string err = mapstructure.Decode(secret.Data[path], &res) if err != nil { return nil, err } if len(res) == 0 { _, ok := secret.Data["capabilities"] if ok { err = mapstructure.Decode(secret.Data["capabilities"], &res) if err != nil { return nil, err } } } return res, nil } func (c *Sys) CapabilitiesAccessor(accessor, path string) ([]string, error) { return c.CapabilitiesAccessorWithContext(context.Background(), accessor, path) } func (c *Sys) CapabilitiesAccessorWithContext(ctx context.Context, accessor, path string) ([]string, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() body := map[string]string{ "accessor": accessor, "path": path, } reqPath := "/v1/sys/capabilities-accessor" r := c.c.NewRequest(http.MethodPost, reqPath) if err := r.SetJSONBody(body); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } var res []string err = mapstructure.Decode(secret.Data[path], &res) if err != nil { return nil, err } if len(res) == 0 { _, ok := secret.Data["capabilities"] if ok { err = mapstructure.Decode(secret.Data["capabilities"], &res) if err != nil { return nil, err } } } return res, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_config_cors.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "errors" "net/http" "github.com/mitchellh/mapstructure" ) func (c *Sys) CORSStatus() (*CORSResponse, error) { return c.CORSStatusWithContext(context.Background()) } func (c *Sys) CORSStatusWithContext(ctx context.Context) (*CORSResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, "/v1/sys/config/cors") resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } var result CORSResponse err = mapstructure.Decode(secret.Data, &result) if err != nil { return nil, err } return &result, err } func (c *Sys) ConfigureCORS(req *CORSRequest) error { return c.ConfigureCORSWithContext(context.Background(), req) } func (c *Sys) ConfigureCORSWithContext(ctx context.Context, req *CORSRequest) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPut, "/v1/sys/config/cors") if err := r.SetJSONBody(req); err != nil { return err } resp, err := c.c.rawRequestWithContext(ctx, r) if err == nil { defer resp.Body.Close() } return err } func (c *Sys) DisableCORS() error { return c.DisableCORSWithContext(context.Background()) } func (c *Sys) DisableCORSWithContext(ctx context.Context) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodDelete, "/v1/sys/config/cors") resp, err := c.c.rawRequestWithContext(ctx, r) if err == nil { defer resp.Body.Close() } return err } type CORSRequest struct { AllowedOrigins []string `json:"allowed_origins" mapstructure:"allowed_origins"` AllowedHeaders []string `json:"allowed_headers" mapstructure:"allowed_headers"` Enabled bool `json:"enabled" mapstructure:"enabled"` } type CORSResponse struct { AllowedOrigins []string `json:"allowed_origins" mapstructure:"allowed_origins"` AllowedHeaders []string `json:"allowed_headers" mapstructure:"allowed_headers"` Enabled bool `json:"enabled" mapstructure:"enabled"` } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_generate_root.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "net/http" ) func (c *Sys) GenerateRootStatus() (*GenerateRootStatusResponse, error) { return c.GenerateRootStatusWithContext(context.Background()) } func (c *Sys) GenerateDROperationTokenStatus() (*GenerateRootStatusResponse, error) { return c.GenerateDROperationTokenStatusWithContext(context.Background()) } func (c *Sys) GenerateRecoveryOperationTokenStatus() (*GenerateRootStatusResponse, error) { return c.GenerateRecoveryOperationTokenStatusWithContext(context.Background()) } func (c *Sys) GenerateRootStatusWithContext(ctx context.Context) (*GenerateRootStatusResponse, error) { return c.generateRootStatusCommonWithContext(ctx, "/v1/sys/generate-root/attempt") } func (c *Sys) GenerateDROperationTokenStatusWithContext(ctx context.Context) (*GenerateRootStatusResponse, error) { return c.generateRootStatusCommonWithContext(ctx, "/v1/sys/replication/dr/secondary/generate-operation-token/attempt") } func (c *Sys) GenerateRecoveryOperationTokenStatusWithContext(ctx context.Context) (*GenerateRootStatusResponse, error) { return c.generateRootStatusCommonWithContext(ctx, "/v1/sys/generate-recovery-token/attempt") } func (c *Sys) generateRootStatusCommonWithContext(ctx context.Context, path string) (*GenerateRootStatusResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, path) resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() var result GenerateRootStatusResponse err = resp.DecodeJSON(&result) return &result, err } func (c *Sys) GenerateRootInit(otp, pgpKey string) (*GenerateRootStatusResponse, error) { return c.GenerateRootInitWithContext(context.Background(), otp, pgpKey) } func (c *Sys) GenerateDROperationTokenInit(otp, pgpKey string) (*GenerateRootStatusResponse, error) { return c.GenerateDROperationTokenInitWithContext(context.Background(), otp, pgpKey) } func (c *Sys) GenerateRecoveryOperationTokenInit(otp, pgpKey string) (*GenerateRootStatusResponse, error) { return c.GenerateRecoveryOperationTokenInitWithContext(context.Background(), otp, pgpKey) } func (c *Sys) GenerateRootInitWithContext(ctx context.Context, otp, pgpKey string) (*GenerateRootStatusResponse, error) { return c.generateRootInitCommonWithContext(ctx, "/v1/sys/generate-root/attempt", otp, pgpKey) } func (c *Sys) GenerateDROperationTokenInitWithContext(ctx context.Context, otp, pgpKey string) (*GenerateRootStatusResponse, error) { return c.generateRootInitCommonWithContext(ctx, "/v1/sys/replication/dr/secondary/generate-operation-token/attempt", otp, pgpKey) } func (c *Sys) GenerateRecoveryOperationTokenInitWithContext(ctx context.Context, otp, pgpKey string) (*GenerateRootStatusResponse, error) { return c.generateRootInitCommonWithContext(ctx, "/v1/sys/generate-recovery-token/attempt", otp, pgpKey) } func (c *Sys) generateRootInitCommonWithContext(ctx context.Context, path, otp, pgpKey string) (*GenerateRootStatusResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() body := map[string]interface{}{ "otp": otp, "pgp_key": pgpKey, } r := c.c.NewRequest(http.MethodPut, path) if err := r.SetJSONBody(body); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() var result GenerateRootStatusResponse err = resp.DecodeJSON(&result) return &result, err } func (c *Sys) GenerateRootCancel() error { return c.GenerateRootCancelWithContext(context.Background()) } func (c *Sys) GenerateDROperationTokenCancel() error { return c.GenerateDROperationTokenCancelWithContext(context.Background()) } func (c *Sys) GenerateRecoveryOperationTokenCancel() error { return c.GenerateRecoveryOperationTokenCancelWithContext(context.Background()) } func (c *Sys) GenerateRootCancelWithContext(ctx context.Context) error { return c.generateRootCancelCommonWithContext(ctx, "/v1/sys/generate-root/attempt") } func (c *Sys) GenerateDROperationTokenCancelWithContext(ctx context.Context) error { return c.generateRootCancelCommonWithContext(ctx, "/v1/sys/replication/dr/secondary/generate-operation-token/attempt") } func (c *Sys) GenerateRecoveryOperationTokenCancelWithContext(ctx context.Context) error { return c.generateRootCancelCommonWithContext(ctx, "/v1/sys/generate-recovery-token/attempt") } func (c *Sys) generateRootCancelCommonWithContext(ctx context.Context, path string) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodDelete, path) resp, err := c.c.rawRequestWithContext(ctx, r) if err == nil { defer resp.Body.Close() } return err } func (c *Sys) GenerateRootUpdate(shard, nonce string) (*GenerateRootStatusResponse, error) { return c.GenerateRootUpdateWithContext(context.Background(), shard, nonce) } func (c *Sys) GenerateDROperationTokenUpdate(shard, nonce string) (*GenerateRootStatusResponse, error) { return c.GenerateDROperationTokenUpdateWithContext(context.Background(), shard, nonce) } func (c *Sys) GenerateRecoveryOperationTokenUpdate(shard, nonce string) (*GenerateRootStatusResponse, error) { return c.GenerateRecoveryOperationTokenUpdateWithContext(context.Background(), shard, nonce) } func (c *Sys) GenerateRootUpdateWithContext(ctx context.Context, shard, nonce string) (*GenerateRootStatusResponse, error) { return c.generateRootUpdateCommonWithContext(ctx, "/v1/sys/generate-root/update", shard, nonce) } func (c *Sys) GenerateDROperationTokenUpdateWithContext(ctx context.Context, shard, nonce string) (*GenerateRootStatusResponse, error) { return c.generateRootUpdateCommonWithContext(ctx, "/v1/sys/replication/dr/secondary/generate-operation-token/update", shard, nonce) } func (c *Sys) GenerateRecoveryOperationTokenUpdateWithContext(ctx context.Context, shard, nonce string) (*GenerateRootStatusResponse, error) { return c.generateRootUpdateCommonWithContext(ctx, "/v1/sys/generate-recovery-token/update", shard, nonce) } func (c *Sys) generateRootUpdateCommonWithContext(ctx context.Context, path, shard, nonce string) (*GenerateRootStatusResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() body := map[string]interface{}{ "key": shard, "nonce": nonce, } r := c.c.NewRequest(http.MethodPut, path) if err := r.SetJSONBody(body); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() var result GenerateRootStatusResponse err = resp.DecodeJSON(&result) return &result, err } type GenerateRootStatusResponse struct { Nonce string `json:"nonce"` Started bool `json:"started"` Progress int `json:"progress"` Required int `json:"required"` Complete bool `json:"complete"` EncodedToken string `json:"encoded_token"` EncodedRootToken string `json:"encoded_root_token"` PGPFingerprint string `json:"pgp_fingerprint"` OTP string `json:"otp"` OTPLength int `json:"otp_length"` } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_hastatus.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "net/http" "time" ) func (c *Sys) HAStatus() (*HAStatusResponse, error) { return c.HAStatusWithContext(context.Background()) } func (c *Sys) HAStatusWithContext(ctx context.Context) (*HAStatusResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, "/v1/sys/ha-status") resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() var result HAStatusResponse err = resp.DecodeJSON(&result) return &result, err } type HAStatusResponse struct { Nodes []HANode } type HANode struct { Hostname string `json:"hostname"` APIAddress string `json:"api_address"` ClusterAddress string `json:"cluster_address"` ActiveNode bool `json:"active_node"` LastEcho *time.Time `json:"last_echo"` EchoDurationMillis int64 `json:"echo_duration_ms"` ClockSkewMillis int64 `json:"clock_skew_ms"` Version string `json:"version"` UpgradeVersion string `json:"upgrade_version,omitempty"` RedundancyZone string `json:"redundancy_zone,omitempty"` ReplicationPrimaryCanaryAgeMillis int64 `json:"replication_primary_canary_age_ms"` } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_health.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "net/http" ) func (c *Sys) Health() (*HealthResponse, error) { return c.HealthWithContext(context.Background()) } func (c *Sys) HealthWithContext(ctx context.Context) (*HealthResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, "/v1/sys/health") // If the code is 400 or above it will automatically turn into an error, // but the sys/health API defaults to returning 5xx when not sealed or // inited, so we force this code to be something else so we parse correctly r.Params.Add("uninitcode", "299") r.Params.Add("sealedcode", "299") r.Params.Add("standbycode", "299") r.Params.Add("drsecondarycode", "299") r.Params.Add("performancestandbycode", "299") r.Params.Add("removedcode", "299") r.Params.Add("haunhealthycode", "299") resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() var result HealthResponse err = resp.DecodeJSON(&result) return &result, err } type HealthResponse struct { Initialized bool `json:"initialized"` Sealed bool `json:"sealed"` Standby bool `json:"standby"` PerformanceStandby bool `json:"performance_standby"` ReplicationPerformanceMode string `json:"replication_performance_mode"` ReplicationDRMode string `json:"replication_dr_mode"` ServerTimeUTC int64 `json:"server_time_utc"` Version string `json:"version"` ClusterName string `json:"cluster_name,omitempty"` ClusterID string `json:"cluster_id,omitempty"` LastWAL uint64 `json:"last_wal,omitempty"` Enterprise bool `json:"enterprise"` EchoDurationMillis int64 `json:"echo_duration_ms"` ClockSkewMillis int64 `json:"clock_skew_ms"` ReplicationPrimaryCanaryAgeMillis int64 `json:"replication_primary_canary_age_ms"` RemovedFromCluster *bool `json:"removed_from_cluster,omitempty"` HAConnectionHealthy *bool `json:"ha_connection_healthy,omitempty"` LastRequestForwardingHeartbeatMillis int64 `json:"last_request_forwarding_heartbeat_ms,omitempty"` } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_init.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "net/http" ) func (c *Sys) InitStatus() (bool, error) { return c.InitStatusWithContext(context.Background()) } func (c *Sys) InitStatusWithContext(ctx context.Context) (bool, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, "/v1/sys/init") resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return false, err } defer resp.Body.Close() var result InitStatusResponse err = resp.DecodeJSON(&result) return result.Initialized, err } func (c *Sys) Init(opts *InitRequest) (*InitResponse, error) { return c.InitWithContext(context.Background(), opts) } func (c *Sys) InitWithContext(ctx context.Context, opts *InitRequest) (*InitResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPut, "/v1/sys/init") if err := r.SetJSONBody(opts); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() var result InitResponse err = resp.DecodeJSON(&result) return &result, err } type InitRequest struct { SecretShares int `json:"secret_shares"` SecretThreshold int `json:"secret_threshold"` StoredShares int `json:"stored_shares"` PGPKeys []string `json:"pgp_keys"` RecoveryShares int `json:"recovery_shares"` RecoveryThreshold int `json:"recovery_threshold"` RecoveryPGPKeys []string `json:"recovery_pgp_keys"` RootTokenPGPKey string `json:"root_token_pgp_key"` } type InitStatusResponse struct { Initialized bool } type InitResponse struct { Keys []string `json:"keys"` KeysB64 []string `json:"keys_base64"` RecoveryKeys []string `json:"recovery_keys"` RecoveryKeysB64 []string `json:"recovery_keys_base64"` RootToken string `json:"root_token"` } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_leader.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "net/http" "time" ) func (c *Sys) Leader() (*LeaderResponse, error) { return c.LeaderWithContext(context.Background()) } func (c *Sys) LeaderWithContext(ctx context.Context) (*LeaderResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, "/v1/sys/leader") resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() var result LeaderResponse err = resp.DecodeJSON(&result) return &result, err } type LeaderResponse struct { HAEnabled bool `json:"ha_enabled"` IsSelf bool `json:"is_self"` ActiveTime time.Time `json:"active_time"` LeaderAddress string `json:"leader_address"` LeaderClusterAddress string `json:"leader_cluster_address"` PerfStandby bool `json:"performance_standby"` PerfStandbyLastRemoteWAL uint64 `json:"performance_standby_last_remote_wal"` LastWAL uint64 `json:"last_wal"` RaftCommittedIndex uint64 `json:"raft_committed_index,omitempty"` RaftAppliedIndex uint64 `json:"raft_applied_index,omitempty"` } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_leases.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "errors" "net/http" ) func (c *Sys) Renew(id string, increment int) (*Secret, error) { return c.RenewWithContext(context.Background(), id, increment) } func (c *Sys) RenewWithContext(ctx context.Context, id string, increment int) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPut, "/v1/sys/leases/renew") body := map[string]interface{}{ "increment": increment, "lease_id": id, } if err := r.SetJSONBody(body); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() return ParseSecret(resp.Body) } func (c *Sys) Lookup(id string) (*Secret, error) { return c.LookupWithContext(context.Background(), id) } func (c *Sys) LookupWithContext(ctx context.Context, id string) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPut, "/v1/sys/leases/lookup") body := map[string]interface{}{ "lease_id": id, } if err := r.SetJSONBody(body); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() return ParseSecret(resp.Body) } func (c *Sys) Revoke(id string) error { return c.RevokeWithContext(context.Background(), id) } func (c *Sys) RevokeWithContext(ctx context.Context, id string) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPut, "/v1/sys/leases/revoke") body := map[string]interface{}{ "lease_id": id, } if err := r.SetJSONBody(body); err != nil { return err } resp, err := c.c.rawRequestWithContext(ctx, r) if err == nil { defer resp.Body.Close() } return err } func (c *Sys) RevokePrefix(id string) error { return c.RevokePrefixWithContext(context.Background(), id) } func (c *Sys) RevokePrefixWithContext(ctx context.Context, id string) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPut, "/v1/sys/leases/revoke-prefix/"+id) resp, err := c.c.rawRequestWithContext(ctx, r) if err == nil { defer resp.Body.Close() } return err } func (c *Sys) RevokeForce(id string) error { return c.RevokeForceWithContext(context.Background(), id) } func (c *Sys) RevokeForceWithContext(ctx context.Context, id string) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPut, "/v1/sys/leases/revoke-force/"+id) resp, err := c.c.rawRequestWithContext(ctx, r) if err == nil { defer resp.Body.Close() } return err } func (c *Sys) RevokeWithOptions(opts *RevokeOptions) error { return c.RevokeWithOptionsWithContext(context.Background(), opts) } func (c *Sys) RevokeWithOptionsWithContext(ctx context.Context, opts *RevokeOptions) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() if opts == nil { return errors.New("nil options provided") } // Construct path path := "/v1/sys/leases/revoke/" switch { case opts.Force: path = "/v1/sys/leases/revoke-force/" case opts.Prefix: path = "/v1/sys/leases/revoke-prefix/" } path += opts.LeaseID r := c.c.NewRequest(http.MethodPut, path) if !opts.Force { body := map[string]interface{}{ "sync": opts.Sync, } if err := r.SetJSONBody(body); err != nil { return err } } resp, err := c.c.rawRequestWithContext(ctx, r) if err == nil { defer resp.Body.Close() } return err } type RevokeOptions struct { LeaseID string Force bool Prefix bool Sync bool } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_mfa.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "fmt" "net/http" ) func (c *Sys) MFAValidate(requestID string, payload map[string]interface{}) (*Secret, error) { return c.MFAValidateWithContext(context.Background(), requestID, payload) } func (c *Sys) MFAValidateWithContext(ctx context.Context, requestID string, payload map[string]interface{}) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() body := map[string]interface{}{ "mfa_request_id": requestID, "mfa_payload": payload, } r := c.c.NewRequest(http.MethodPost, fmt.Sprintf("/v1/sys/mfa/validate")) if err := r.SetJSONBody(body); err != nil { return nil, fmt.Errorf("failed to set request body: %w", err) } resp, err := c.c.rawRequestWithContext(ctx, r) if resp != nil { defer resp.Body.Close() } if err != nil { return nil, err } secret, err := ParseSecret(resp.Body) if err != nil { return nil, fmt.Errorf("failed to parse secret from response: %w", err) } if secret == nil { return nil, fmt.Errorf("data from server response is empty") } return secret, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_monitor.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "bufio" "context" "fmt" "net/http" ) // Monitor returns a channel that outputs strings containing the log messages // coming from the server. func (c *Sys) Monitor(ctx context.Context, logLevel string, logFormat string) (chan string, error) { r := c.c.NewRequest(http.MethodGet, "/v1/sys/monitor") if logLevel == "" { r.Params.Add("log_level", "info") } else { r.Params.Add("log_level", logLevel) } if logFormat == "" { r.Params.Add("log_format", "standard") } else { r.Params.Add("log_format", logFormat) } resp, err := c.c.RawRequestWithContext(ctx, r) if err != nil { return nil, err } logCh := make(chan string, 64) go func() { scanner := bufio.NewScanner(resp.Body) droppedCount := 0 defer close(logCh) defer resp.Body.Close() for { if ctx.Err() != nil { return } if !scanner.Scan() { return } logMessage := scanner.Text() if droppedCount > 0 { select { case logCh <- fmt.Sprintf("Monitor dropped %d logs during monitor request\n", droppedCount): droppedCount = 0 default: droppedCount++ continue } } select { case logCh <- logMessage: default: droppedCount++ } } }() return logCh, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_mounts.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "errors" "fmt" "net/http" "time" "github.com/mitchellh/mapstructure" ) func (c *Sys) GetMount(path string) (*MountOutput, error) { return c.GetMountWithContext(context.Background(), path) } func (c *Sys) GetMountWithContext(ctx context.Context, path string) (*MountOutput, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, fmt.Sprintf("/v1/sys/mounts/%s", path)) resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } mount := MountOutput{} err = mapstructure.Decode(secret.Data, &mount) if err != nil { return nil, err } return &mount, nil } func (c *Sys) ListMounts() (map[string]*MountOutput, error) { return c.ListMountsWithContext(context.Background()) } func (c *Sys) ListMountsWithContext(ctx context.Context) (map[string]*MountOutput, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, "/v1/sys/mounts") resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } mounts := map[string]*MountOutput{} err = mapstructure.Decode(secret.Data, &mounts) if err != nil { return nil, err } return mounts, nil } func (c *Sys) Mount(path string, mountInfo *MountInput) error { return c.MountWithContext(context.Background(), path, mountInfo) } func (c *Sys) MountWithContext(ctx context.Context, path string, mountInfo *MountInput) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPost, fmt.Sprintf("/v1/sys/mounts/%s", path)) if err := r.SetJSONBody(mountInfo); err != nil { return err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return err } defer resp.Body.Close() return nil } func (c *Sys) Unmount(path string) error { return c.UnmountWithContext(context.Background(), path) } func (c *Sys) UnmountWithContext(ctx context.Context, path string) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodDelete, fmt.Sprintf("/v1/sys/mounts/%s", path)) resp, err := c.c.rawRequestWithContext(ctx, r) if err == nil { defer resp.Body.Close() } return err } // Remount wraps RemountWithContext using context.Background. func (c *Sys) Remount(from, to string) error { return c.RemountWithContext(context.Background(), from, to) } // RemountWithContext kicks off a remount operation, polls the status endpoint using // the migration ID till either success or failure state is observed func (c *Sys) RemountWithContext(ctx context.Context, from, to string) error { remountResp, err := c.StartRemountWithContext(ctx, from, to) if err != nil { return err } for { remountStatusResp, err := c.RemountStatusWithContext(ctx, remountResp.MigrationID) if err != nil { return err } if remountStatusResp.MigrationInfo.MigrationStatus == "success" { return nil } if remountStatusResp.MigrationInfo.MigrationStatus == "failure" { return fmt.Errorf("Failure! Error encountered moving mount %s to %s, with migration ID %s", from, to, remountResp.MigrationID) } time.Sleep(1 * time.Second) } } // StartRemount wraps StartRemountWithContext using context.Background. func (c *Sys) StartRemount(from, to string) (*MountMigrationOutput, error) { return c.StartRemountWithContext(context.Background(), from, to) } // StartRemountWithContext kicks off a mount migration and returns a response with the migration ID func (c *Sys) StartRemountWithContext(ctx context.Context, from, to string) (*MountMigrationOutput, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() body := map[string]interface{}{ "from": from, "to": to, } r := c.c.NewRequest(http.MethodPost, "/v1/sys/remount") if err := r.SetJSONBody(body); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } var result MountMigrationOutput err = mapstructure.Decode(secret.Data, &result) if err != nil { return nil, err } return &result, err } // RemountStatus wraps RemountStatusWithContext using context.Background. func (c *Sys) RemountStatus(migrationID string) (*MountMigrationStatusOutput, error) { return c.RemountStatusWithContext(context.Background(), migrationID) } // RemountStatusWithContext checks the status of a mount migration operation with the provided ID func (c *Sys) RemountStatusWithContext(ctx context.Context, migrationID string) (*MountMigrationStatusOutput, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, fmt.Sprintf("/v1/sys/remount/status/%s", migrationID)) resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } var result MountMigrationStatusOutput err = mapstructure.Decode(secret.Data, &result) if err != nil { return nil, err } return &result, err } // TuneMountConfigInput is a pointer-only version of MountConfigInput. This allows proper update calls where only // Values provided by the user are changed, but values can be changed to an empty (but non-nil) value. type TuneMountConfigInput struct { Options *map[string]string `json:"options,omitempty" mapstructure:"options"` DefaultLeaseTTL *string `json:"default_lease_ttl,omitempty" mapstructure:"default_lease_ttl"` Description *string `json:"description,omitempty" mapstructure:"description"` MaxLeaseTTL *string `json:"max_lease_ttl,omitempty" mapstructure:"max_lease_ttl"` ForceNoCache *bool `json:"force_no_cache,omitempty" mapstructure:"force_no_cache"` AuditNonHMACRequestKeys *[]string `json:"audit_non_hmac_request_keys,omitempty" mapstructure:"audit_non_hmac_request_keys"` AuditNonHMACResponseKeys *[]string `json:"audit_non_hmac_response_keys,omitempty" mapstructure:"audit_non_hmac_response_keys"` ListingVisibility *string `json:"listing_visibility,omitempty" mapstructure:"listing_visibility"` PassthroughRequestHeaders *[]string `json:"passthrough_request_headers,omitempty" mapstructure:"passthrough_request_headers"` AllowedResponseHeaders *[]string `json:"allowed_response_headers,omitempty" mapstructure:"allowed_response_headers"` TokenType *string `json:"token_type,omitempty" mapstructure:"token_type"` AllowedManagedKeys *[]string `json:"allowed_managed_keys,omitempty" mapstructure:"allowed_managed_keys"` PluginVersion *string `json:"plugin_version,omitempty"` UserLockoutConfig *TuneUserLockoutConfigInput `json:"user_lockout_config,omitempty"` DelegatedAuthAccessors *[]string `json:"delegated_auth_accessors,omitempty" mapstructure:"delegated_auth_accessors"` IdentityTokenKey *string `json:"identity_token_key,omitempty" mapstructure:"identity_token_key"` TrimRequestTrailingSlashes *bool `json:"trim_request_trailing_slashes,omitempty" mapstructure:"trim_request_trailing_slashes"` // Deprecated: This field will always be blank for newer server responses. PluginName *string `json:"plugin_name,omitempty" mapstructure:"plugin_name"` } type TuneUserLockoutConfigInput struct { LockoutThreshold *string `json:"lockout_threshold,omitempty" structs:"lockout_threshold" mapstructure:"lockout_threshold"` LockoutDuration *string `json:"lockout_duration,omitempty" structs:"lockout_duration" mapstructure:"lockout_duration"` LockoutCounterResetDuration *string `json:"lockout_counter_reset_duration,omitempty" structs:"lockout_counter_reset_duration" mapstructure:"lockout_counter_reset_duration"` DisableLockout *bool `json:"lockout_disable,omitempty" structs:"lockout_disable" mapstructure:"lockout_disable"` } func (c *Sys) TuneMountAllowNil(path string, config TuneMountConfigInput) error { return c.TuneMountAllowNilWithContext(context.Background(), path, config) } // Deprecated: newer functionality should use TuneMountAllowNil instead so that parameters can be set to the nil value func (c *Sys) TuneMount(path string, config MountConfigInput) error { return c.TuneMountWithContext(context.Background(), path, config) } func (c *Sys) TuneMountAllowNilWithContext(ctx context.Context, path string, config TuneMountConfigInput) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPost, fmt.Sprintf("/v1/sys/mounts/%s/tune", path)) if err := r.SetJSONBody(config); err != nil { return err } resp, err := c.c.rawRequestWithContext(ctx, r) if err == nil { defer resp.Body.Close() } return err } // Deprecated: newer functionality should use TuneMountAllowNilWithContext instead, so that configuration can be set to // a nil value. func (c *Sys) TuneMountWithContext(ctx context.Context, path string, config MountConfigInput) error { tuneConfig := TuneMountConfigInput{} tuneConfig.Options = &config.Options // Not omitted if empty tuneConfig.DefaultLeaseTTL = &config.DefaultLeaseTTL // Not omitted if empty tuneConfig.Description = config.Description // Already a pointer value tuneConfig.MaxLeaseTTL = &config.MaxLeaseTTL // Not omitted if empty tuneConfig.ForceNoCache = &config.ForceNoCache // Not omitted if empty if len(config.AuditNonHMACRequestKeys) != 0 { // Because omitempty in the JSON tuneConfig.AuditNonHMACRequestKeys = &config.AuditNonHMACRequestKeys } if len(config.AuditNonHMACResponseKeys) != 0 { // Because omitempty in the JSON tuneConfig.AuditNonHMACResponseKeys = &config.AuditNonHMACResponseKeys } if config.ListingVisibility != "" { // Because omitempty in the JSON tuneConfig.ListingVisibility = &config.ListingVisibility } if len(config.PassthroughRequestHeaders) != 0 { // Because omitempty in the JSON tuneConfig.PassthroughRequestHeaders = &config.PassthroughRequestHeaders } if len(config.AllowedResponseHeaders) != 0 { // Because omitempty in the JSON tuneConfig.AllowedResponseHeaders = &config.AllowedResponseHeaders } if config.TokenType != "" { // Because omitempty in the JSON tuneConfig.TokenType = &config.TokenType } if len(config.AllowedManagedKeys) != 0 { // Because omitempty in the JSON tuneConfig.AllowedManagedKeys = &config.AllowedManagedKeys } if config.PluginVersion != "" { // Because omitempty in the JSON tuneConfig.PluginVersion = &config.PluginVersion } if config.UserLockoutConfig != nil { userLockoutConfig := TuneUserLockoutConfigInput{} if config.UserLockoutConfig.LockoutDuration != "" { userLockoutConfig.LockoutDuration = &config.UserLockoutConfig.LockoutDuration } if config.UserLockoutConfig.LockoutCounterResetDuration != "" { userLockoutConfig.LockoutCounterResetDuration = &config.UserLockoutConfig.LockoutCounterResetDuration } if config.UserLockoutConfig.LockoutThreshold != "" { userLockoutConfig.LockoutThreshold = &config.UserLockoutConfig.LockoutThreshold } if config.UserLockoutConfig.DisableLockout != nil { userLockoutConfig.DisableLockout = config.UserLockoutConfig.DisableLockout } tuneConfig.UserLockoutConfig = &userLockoutConfig } if len(config.DelegatedAuthAccessors) != 0 { // Because omitempty in the JSON tuneConfig.DelegatedAuthAccessors = &config.DelegatedAuthAccessors } if config.IdentityTokenKey != "" { // Because omitempty in the JSON tuneConfig.IdentityTokenKey = &config.IdentityTokenKey } tuneConfig.TrimRequestTrailingSlashes = config.TrimRequestTrailingSlashes // Already a pointer despite being omitempty if config.PluginName != "" { // Because omitempty in the JSON tuneConfig.PluginName = &config.PluginName } return c.TuneMountAllowNilWithContext(ctx, path, tuneConfig) } func (c *Sys) MountConfig(path string) (*MountConfigOutput, error) { return c.MountConfigWithContext(context.Background(), path) } func (c *Sys) MountConfigWithContext(ctx context.Context, path string) (*MountConfigOutput, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, fmt.Sprintf("/v1/sys/mounts/%s/tune", path)) resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } var result MountConfigOutput err = mapstructure.Decode(secret.Data, &result) if err != nil { return nil, err } return &result, err } type MountInput struct { Type string `json:"type"` Description string `json:"description"` Config MountConfigInput `json:"config"` Local bool `json:"local"` SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"` ExternalEntropyAccess bool `json:"external_entropy_access" mapstructure:"external_entropy_access"` Options map[string]string `json:"options"` // Deprecated: Newer server responses should be returning this information in the // Type field (json: "type") instead. PluginName string `json:"plugin_name,omitempty"` } type MountConfigInput struct { Options map[string]string `json:"options" mapstructure:"options"` DefaultLeaseTTL string `json:"default_lease_ttl" mapstructure:"default_lease_ttl"` Description *string `json:"description,omitempty" mapstructure:"description"` MaxLeaseTTL string `json:"max_lease_ttl" mapstructure:"max_lease_ttl"` ForceNoCache bool `json:"force_no_cache" mapstructure:"force_no_cache"` AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" mapstructure:"audit_non_hmac_request_keys"` AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" mapstructure:"audit_non_hmac_response_keys"` ListingVisibility string `json:"listing_visibility,omitempty" mapstructure:"listing_visibility"` PassthroughRequestHeaders []string `json:"passthrough_request_headers,omitempty" mapstructure:"passthrough_request_headers"` AllowedResponseHeaders []string `json:"allowed_response_headers,omitempty" mapstructure:"allowed_response_headers"` TokenType string `json:"token_type,omitempty" mapstructure:"token_type"` AllowedManagedKeys []string `json:"allowed_managed_keys,omitempty" mapstructure:"allowed_managed_keys"` PluginVersion string `json:"plugin_version,omitempty"` UserLockoutConfig *UserLockoutConfigInput `json:"user_lockout_config,omitempty"` DelegatedAuthAccessors []string `json:"delegated_auth_accessors,omitempty" mapstructure:"delegated_auth_accessors"` IdentityTokenKey string `json:"identity_token_key,omitempty" mapstructure:"identity_token_key"` TrimRequestTrailingSlashes *bool `json:"trim_request_trailing_slashes,omitempty" mapstructure:"trim_request_trailing_slashes"` // Deprecated: This field will always be blank for newer server responses. PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"` } type MountOutput struct { UUID string `json:"uuid"` Type string `json:"type"` Description string `json:"description"` Accessor string `json:"accessor"` Config MountConfigOutput `json:"config"` Options map[string]string `json:"options"` Local bool `json:"local"` SealWrap bool `json:"seal_wrap" mapstructure:"seal_wrap"` ExternalEntropyAccess bool `json:"external_entropy_access" mapstructure:"external_entropy_access"` PluginVersion string `json:"plugin_version" mapstructure:"plugin_version"` RunningVersion string `json:"running_plugin_version" mapstructure:"running_plugin_version"` RunningSha256 string `json:"running_sha256" mapstructure:"running_sha256"` DeprecationStatus string `json:"deprecation_status" mapstructure:"deprecation_status"` } type MountConfigOutput struct { DefaultLeaseTTL int `json:"default_lease_ttl" mapstructure:"default_lease_ttl"` MaxLeaseTTL int `json:"max_lease_ttl" mapstructure:"max_lease_ttl"` ForceNoCache bool `json:"force_no_cache" mapstructure:"force_no_cache"` AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" mapstructure:"audit_non_hmac_request_keys"` AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" mapstructure:"audit_non_hmac_response_keys"` ListingVisibility string `json:"listing_visibility,omitempty" mapstructure:"listing_visibility"` PassthroughRequestHeaders []string `json:"passthrough_request_headers,omitempty" mapstructure:"passthrough_request_headers"` AllowedResponseHeaders []string `json:"allowed_response_headers,omitempty" mapstructure:"allowed_response_headers"` TokenType string `json:"token_type,omitempty" mapstructure:"token_type"` AllowedManagedKeys []string `json:"allowed_managed_keys,omitempty" mapstructure:"allowed_managed_keys"` UserLockoutConfig *UserLockoutConfigOutput `json:"user_lockout_config,omitempty"` DelegatedAuthAccessors []string `json:"delegated_auth_accessors,omitempty" mapstructure:"delegated_auth_accessors"` IdentityTokenKey string `json:"identity_token_key,omitempty" mapstructure:"identity_token_key"` TrimRequestTrailingSlashes bool `json:"trim_request_trailing_slashes,omitempty" mapstructure:"trim_request_trailing_slashes"` // Deprecated: This field will always be blank for newer server responses. PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"` } type UserLockoutConfigInput struct { LockoutThreshold string `json:"lockout_threshold,omitempty" structs:"lockout_threshold" mapstructure:"lockout_threshold"` LockoutDuration string `json:"lockout_duration,omitempty" structs:"lockout_duration" mapstructure:"lockout_duration"` LockoutCounterResetDuration string `json:"lockout_counter_reset_duration,omitempty" structs:"lockout_counter_reset_duration" mapstructure:"lockout_counter_reset_duration"` DisableLockout *bool `json:"lockout_disable,omitempty" structs:"lockout_disable" mapstructure:"lockout_disable"` } type UserLockoutConfigOutput struct { LockoutThreshold uint `json:"lockout_threshold,omitempty" structs:"lockout_threshold" mapstructure:"lockout_threshold"` LockoutDuration int `json:"lockout_duration,omitempty" structs:"lockout_duration" mapstructure:"lockout_duration"` LockoutCounterReset int `json:"lockout_counter_reset,omitempty" structs:"lockout_counter_reset" mapstructure:"lockout_counter_reset"` DisableLockout *bool `json:"disable_lockout,omitempty" structs:"disable_lockout" mapstructure:"disable_lockout"` } type MountMigrationOutput struct { MigrationID string `mapstructure:"migration_id"` } type MountMigrationStatusOutput struct { MigrationID string `mapstructure:"migration_id"` MigrationInfo *MountMigrationStatusInfo `mapstructure:"migration_info"` } type MountMigrationStatusInfo struct { SourceMount string `mapstructure:"source_mount"` TargetMount string `mapstructure:"target_mount"` MigrationStatus string `mapstructure:"status"` } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_plugins.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "errors" "fmt" "net/http" "strings" "time" "github.com/mitchellh/mapstructure" ) // ListPluginsInput is used as input to the ListPlugins function. type ListPluginsInput struct { // Type of the plugin. Required. Type PluginType `json:"type"` } // ListPluginsResponse is the response from the ListPlugins call. type ListPluginsResponse struct { // PluginsByType is the list of plugins by type. PluginsByType map[PluginType][]string `json:"types"` Details []PluginDetails `json:"details,omitempty"` // Names is the list of names of the plugins. // // Deprecated: Newer server responses should be returning PluginsByType (json: // "types") instead. Names []string `json:"names"` } type PluginDetails struct { Type string `json:"type"` Name string `json:"name"` OCIImage string `json:"oci_image,omitempty" mapstructure:"oci_image"` Runtime string `json:"runtime,omitempty"` Version string `json:"version,omitempty"` Builtin bool `json:"builtin"` DeprecationStatus string `json:"deprecation_status,omitempty" mapstructure:"deprecation_status"` } // ListPlugins wraps ListPluginsWithContext using context.Background. func (c *Sys) ListPlugins(i *ListPluginsInput) (*ListPluginsResponse, error) { return c.ListPluginsWithContext(context.Background(), i) } // ListPluginsWithContext lists all plugins in the catalog and returns their names as a // list of strings. func (c *Sys) ListPluginsWithContext(ctx context.Context, i *ListPluginsInput) (*ListPluginsResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() resp, err := c.c.rawRequestWithContext(ctx, c.c.NewRequest(http.MethodGet, "/v1/sys/plugins/catalog")) if err != nil && resp == nil { return nil, err } if resp == nil { return nil, nil } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } result := &ListPluginsResponse{ PluginsByType: make(map[PluginType][]string), } switch i.Type { case PluginTypeUnknown: for _, pluginType := range PluginTypes { pluginsRaw, ok := secret.Data[pluginType.String()] if !ok { continue } pluginsIfc, ok := pluginsRaw.([]interface{}) if !ok { return nil, fmt.Errorf("unable to parse plugins for %q type", pluginType.String()) } plugins := make([]string, 0, len(pluginsIfc)) for _, nameIfc := range pluginsIfc { name, ok := nameIfc.(string) if !ok { continue } plugins = append(plugins, name) } result.PluginsByType[pluginType] = plugins } default: pluginsRaw, ok := secret.Data[i.Type.String()] if !ok { return nil, fmt.Errorf("no %s entry in returned data", i.Type.String()) } var respKeys []string if err := mapstructure.Decode(pluginsRaw, &respKeys); err != nil { return nil, err } result.PluginsByType[i.Type] = respKeys } if detailed, ok := secret.Data["detailed"]; ok { var details []PluginDetails if err := mapstructure.Decode(detailed, &details); err != nil { return nil, err } switch i.Type { case PluginTypeUnknown: result.Details = details default: // Filter for just the queried type. for _, entry := range details { if entry.Type == i.Type.String() { result.Details = append(result.Details, entry) } } } } return result, nil } // GetPluginInput is used as input to the GetPlugin function. type GetPluginInput struct { Name string `json:"-"` // Type of the plugin. Required. Type PluginType `json:"type"` Version string `json:"version"` } // GetPluginResponse is the response from the GetPlugin call. type GetPluginResponse struct { Args []string `json:"args"` Builtin bool `json:"builtin"` Command string `json:"command"` Name string `json:"name"` SHA256 string `json:"sha256"` OCIImage string `json:"oci_image,omitempty"` Runtime string `json:"runtime,omitempty"` DeprecationStatus string `json:"deprecation_status,omitempty"` Version string `json:"version,omitempty"` } // GetPlugin wraps GetPluginWithContext using context.Background. func (c *Sys) GetPlugin(i *GetPluginInput) (*GetPluginResponse, error) { return c.GetPluginWithContext(context.Background(), i) } // GetPluginWithContext retrieves information about the plugin. func (c *Sys) GetPluginWithContext(ctx context.Context, i *GetPluginInput) (*GetPluginResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() path := catalogPathByType(i.Type, i.Name) req := c.c.NewRequest(http.MethodGet, path) if i.Version != "" { req.Params.Set("version", i.Version) } resp, err := c.c.rawRequestWithContext(ctx, req) if err != nil { return nil, err } defer resp.Body.Close() var result struct { Data *GetPluginResponse } err = resp.DecodeJSON(&result) if err != nil { return nil, err } return result.Data, err } // RegisterPluginInput is used as input to the RegisterPlugin function. type RegisterPluginInput struct { // Name is the name of the plugin. Required. Name string `json:"-"` // Type of the plugin. Required. Type PluginType `json:"type"` // Args is the list of args to spawn the process with. Args []string `json:"args,omitempty"` // Command is the command to run. Command string `json:"command,omitempty"` // SHA256 is the shasum of the plugin. SHA256 string `json:"sha256,omitempty"` // Version is the optional version of the plugin being registered Version string `json:"version,omitempty"` // OCIImage specifies the container image to run as a plugin. OCIImage string `json:"oci_image,omitempty"` // Runtime is the Vault plugin runtime to use when running the plugin. Runtime string `json:"runtime,omitempty"` // Env specifies a list of key=value pairs to add to the plugin's environment // variables. Env []string `json:"env,omitempty"` // Download the plugin when set to true. This is only applicable for external plugins. Download bool `json:"download,omitempty"` } // RegisterPluginResponse is the response from the RegisterPluginDetailed call. type RegisterPluginResponse struct { Warnings []string `json:"warnings"` } // RegisterPlugin wraps RegisterPluginWithContext using context.Background. // Deprecated: Use RegisterPluginDetailed instead. func (c *Sys) RegisterPlugin(i *RegisterPluginInput) error { return c.RegisterPluginWithContext(context.Background(), i) } // RegisterPluginWithContext registers the plugin with the given information. // Deprecated: Use RegisterPluginWithContextDetailed instead. func (c *Sys) RegisterPluginWithContext(ctx context.Context, i *RegisterPluginInput) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() path := catalogPathByType(i.Type, i.Name) req := c.c.NewRequest(http.MethodPut, path) if err := req.SetJSONBody(i); err != nil { return err } resp, err := c.c.rawRequestWithContext(ctx, req) if err == nil { defer resp.Body.Close() } return err } // RegisterPluginDetailed wraps RegisterPluginWtihContextDetailed using context.Background. func (c *Sys) RegisterPluginDetailed(i *RegisterPluginInput) (*RegisterPluginResponse, error) { return c.RegisterPluginWithContextDetailed(context.Background(), i) } // RegisterPluginWithContextDetailed registers the plugin with the given information. func (c *Sys) RegisterPluginWithContextDetailed(ctx context.Context, i *RegisterPluginInput) (*RegisterPluginResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() path := catalogPathByType(i.Type, i.Name) req := c.c.NewRequest(http.MethodPut, path) if err := req.SetJSONBody(i); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, req) if resp != nil { defer resp.Body.Close() } if err != nil { return nil, err } var registerResp RegisterPluginResponse if resp != nil && resp.StatusCode != http.StatusNoContent { if err := resp.DecodeJSON(®isterResp); err != nil { return nil, err } } // Filter out the `Endpoint replaced the value of these parameters with the values captured from the endpoint's path: [type]` // warning because it is expected behavior from this function, as we set the type parameter in both the path and request body, // and the warning informs us the path parameter takes precedence. However, this warning is not relevant for an end user so we // omit it before returning to any client. // TODO: This can likely be removed once https://hashicorp.atlassian.net/browse/VAULT-36722 is addressed. var filteredWarnings []string if len(registerResp.Warnings) > 0 { filteredWarnings = make([]string, 0, len(registerResp.Warnings)) } for _, warning := range registerResp.Warnings { if !strings.Contains(warning, "Endpoint replaced the value of these parameters with the values captured from the endpoint's path") { filteredWarnings = append(filteredWarnings, warning) } } registerResp.Warnings = filteredWarnings return ®isterResp, err } // DeregisterPluginInput is used as input to the DeregisterPlugin function. type DeregisterPluginInput struct { // Name is the name of the plugin. Required. Name string `json:"-"` // Type of the plugin. Required. Type PluginType `json:"type"` // Version of the plugin. Optional. Version string `json:"version,omitempty"` } // DeregisterPlugin wraps DeregisterPluginWithContext using context.Background. func (c *Sys) DeregisterPlugin(i *DeregisterPluginInput) error { return c.DeregisterPluginWithContext(context.Background(), i) } // DeregisterPluginWithContext removes the plugin with the given name from the plugin // catalog. func (c *Sys) DeregisterPluginWithContext(ctx context.Context, i *DeregisterPluginInput) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() path := catalogPathByType(i.Type, i.Name) req := c.c.NewRequest(http.MethodDelete, path) req.Params.Set("version", i.Version) resp, err := c.c.rawRequestWithContext(ctx, req) if err == nil { defer resp.Body.Close() } return err } // RootReloadPluginInput is used as input to the RootReloadPlugin function. type RootReloadPluginInput struct { Plugin string `json:"-"` // Plugin name, as registered in the plugin catalog. Type PluginType `json:"-"` // Plugin type: auth, secret, or database. Scope string `json:"scope,omitempty"` // Empty to reload on current node, "global" for all nodes. } // RootReloadPlugin reloads plugins, possibly returning reloadID for a global // scoped reload. This is only available in the root namespace, and reloads // plugins across all namespaces, whereas ReloadPlugin is available in all // namespaces but only reloads plugins in use in the request's namespace. func (c *Sys) RootReloadPlugin(ctx context.Context, i *RootReloadPluginInput) (string, error) { path := fmt.Sprintf("/v1/sys/plugins/reload/%s/%s", i.Type.String(), i.Plugin) return c.reloadPluginInternal(ctx, path, i, i.Scope == "global") } // ReloadPluginInput is used as input to the ReloadPlugin function. type ReloadPluginInput struct { // Plugin is the name of the plugin to reload, as registered in the plugin catalog Plugin string `json:"plugin"` // Mounts is the array of string mount paths of the plugin backends to reload Mounts []string `json:"mounts"` // Scope is the scope of the plugin reload Scope string `json:"scope"` } // ReloadPlugin wraps ReloadPluginWithContext using context.Background. func (c *Sys) ReloadPlugin(i *ReloadPluginInput) (string, error) { return c.ReloadPluginWithContext(context.Background(), i) } // ReloadPluginWithContext reloads mounted plugin backends, possibly returning // reloadID for a cluster scoped reload. It is limited to reloading plugins that // are in use in the request's namespace. See RootReloadPlugin for an API that // can reload plugins across all namespaces. func (c *Sys) ReloadPluginWithContext(ctx context.Context, i *ReloadPluginInput) (string, error) { return c.reloadPluginInternal(ctx, "/v1/sys/plugins/reload/backend", i, i.Scope == "global") } func (c *Sys) reloadPluginInternal(ctx context.Context, path string, body any, global bool) (string, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() req := c.c.NewRequest(http.MethodPut, path) if err := req.SetJSONBody(body); err != nil { return "", err } resp, err := c.c.rawRequestWithContext(ctx, req) if err != nil { return "", err } defer resp.Body.Close() if global { // Get the reload id secret, parseErr := ParseSecret(resp.Body) if parseErr != nil { return "", parseErr } if _, ok := secret.Data["reload_id"]; ok { return secret.Data["reload_id"].(string), nil } } return "", err } // ReloadStatus is the status of an individual node's plugin reload type ReloadStatus struct { Timestamp time.Time `json:"timestamp" mapstructure:"timestamp"` Error string `json:"error" mapstructure:"error"` } // ReloadStatusResponse is the combined response of all known completed plugin reloads type ReloadStatusResponse struct { ReloadID string `mapstructure:"reload_id"` Results map[string]*ReloadStatus `mapstructure:"results"` } // ReloadPluginStatusInput is used as input to the ReloadStatusPlugin function. type ReloadPluginStatusInput struct { // ReloadID is the ID of the reload operation ReloadID string `json:"reload_id"` } // ReloadPluginStatus wraps ReloadPluginStatusWithContext using context.Background. func (c *Sys) ReloadPluginStatus(reloadStatusInput *ReloadPluginStatusInput) (*ReloadStatusResponse, error) { return c.ReloadPluginStatusWithContext(context.Background(), reloadStatusInput) } // ReloadPluginStatusWithContext retrieves the status of a reload operation func (c *Sys) ReloadPluginStatusWithContext(ctx context.Context, reloadStatusInput *ReloadPluginStatusInput) (*ReloadStatusResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() path := "/v1/sys/plugins/reload/backend/status" req := c.c.NewRequest(http.MethodGet, path) req.Params.Add("reload_id", reloadStatusInput.ReloadID) resp, err := c.c.rawRequestWithContext(ctx, req) if err != nil { return nil, err } defer resp.Body.Close() if resp != nil { secret, parseErr := ParseSecret(resp.Body) if parseErr != nil { return nil, err } var r ReloadStatusResponse d, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ DecodeHook: mapstructure.StringToTimeHookFunc(time.RFC3339), Result: &r, }) if err != nil { return nil, err } err = d.Decode(secret.Data) if err != nil { return nil, err } return &r, nil } return nil, nil } // catalogPathByType is a helper to construct the proper API path by plugin type func catalogPathByType(pluginType PluginType, name string) string { path := fmt.Sprintf("/v1/sys/plugins/catalog/%s/%s", pluginType, name) // Backwards compat, if type is not provided then use old path if pluginType == PluginTypeUnknown { path = fmt.Sprintf("/v1/sys/plugins/catalog/%s", name) } return path } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_plugins_runtimes.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "errors" "fmt" "net/http" "github.com/mitchellh/mapstructure" ) // GetPluginRuntimeInput is used as input to the GetPluginRuntime function. type GetPluginRuntimeInput struct { Name string `json:"-"` // Type of the plugin runtime. Required. Type PluginRuntimeType `json:"type"` } // GetPluginRuntimeResponse is the response from the GetPluginRuntime call. type GetPluginRuntimeResponse struct { Type string `json:"type"` Name string `json:"name"` OCIRuntime string `json:"oci_runtime"` CgroupParent string `json:"cgroup_parent"` CPU int64 `json:"cpu_nanos"` Memory int64 `json:"memory_bytes"` } // GetPluginRuntime retrieves information about the plugin. func (c *Sys) GetPluginRuntime(ctx context.Context, i *GetPluginRuntimeInput) (*GetPluginRuntimeResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() path := pluginRuntimeCatalogPathByType(i.Type, i.Name) req := c.c.NewRequest(http.MethodGet, path) resp, err := c.c.rawRequestWithContext(ctx, req) if err != nil { return nil, err } defer resp.Body.Close() var result struct { Data *GetPluginRuntimeResponse } err = resp.DecodeJSON(&result) if err != nil { return nil, err } return result.Data, err } // RegisterPluginRuntimeInput is used as input to the RegisterPluginRuntime function. type RegisterPluginRuntimeInput struct { // Name is the name of the plugin. Required. Name string `json:"-"` // Type of the plugin. Required. Type PluginRuntimeType `json:"type"` OCIRuntime string `json:"oci_runtime,omitempty"` CgroupParent string `json:"cgroup_parent,omitempty"` CPU int64 `json:"cpu_nanos,omitempty"` Memory int64 `json:"memory_bytes,omitempty"` Rootless bool `json:"rootless,omitempty"` } // RegisterPluginRuntime registers the plugin with the given information. func (c *Sys) RegisterPluginRuntime(ctx context.Context, i *RegisterPluginRuntimeInput) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() path := pluginRuntimeCatalogPathByType(i.Type, i.Name) req := c.c.NewRequest(http.MethodPut, path) if err := req.SetJSONBody(i); err != nil { return err } resp, err := c.c.rawRequestWithContext(ctx, req) if err == nil { defer resp.Body.Close() } return err } // DeregisterPluginRuntimeInput is used as input to the DeregisterPluginRuntime function. type DeregisterPluginRuntimeInput struct { // Name is the name of the plugin runtime. Required. Name string `json:"-"` // Type of the plugin. Required. Type PluginRuntimeType `json:"type"` } // DeregisterPluginRuntime removes the plugin with the given name from the plugin // catalog. func (c *Sys) DeregisterPluginRuntime(ctx context.Context, i *DeregisterPluginRuntimeInput) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() path := pluginRuntimeCatalogPathByType(i.Type, i.Name) req := c.c.NewRequest(http.MethodDelete, path) resp, err := c.c.rawRequestWithContext(ctx, req) if err == nil { defer resp.Body.Close() } return err } type PluginRuntimeDetails struct { Type string `json:"type" mapstructure:"type"` Name string `json:"name" mapstructure:"name"` OCIRuntime string `json:"oci_runtime" mapstructure:"oci_runtime"` CgroupParent string `json:"cgroup_parent" mapstructure:"cgroup_parent"` CPU int64 `json:"cpu_nanos" mapstructure:"cpu_nanos"` Memory int64 `json:"memory_bytes" mapstructure:"memory_bytes"` } // ListPluginRuntimesInput is used as input to the ListPluginRuntimes function. type ListPluginRuntimesInput struct { // Type of the plugin. Required. Type PluginRuntimeType `json:"type"` } // ListPluginRuntimesResponse is the response from the ListPluginRuntimes call. type ListPluginRuntimesResponse struct { // RuntimesByType is the list of plugin runtimes by type. Runtimes []PluginRuntimeDetails `json:"runtimes"` } // ListPluginRuntimes lists all plugin runtimes in the catalog and returns their names as a // list of strings. func (c *Sys) ListPluginRuntimes(ctx context.Context, input *ListPluginRuntimesInput) (*ListPluginRuntimesResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() if input != nil && input.Type == PluginRuntimeTypeUnsupported { return nil, fmt.Errorf("%q is not a supported runtime type", input.Type.String()) } resp, err := c.c.rawRequestWithContext(ctx, c.c.NewRequest(http.MethodGet, "/v1/sys/plugins/runtimes/catalog")) if err != nil && resp == nil { return nil, err } if resp == nil { return nil, nil } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } if _, ok := secret.Data["runtimes"]; !ok { return nil, fmt.Errorf("data from server response does not contain runtimes") } var runtimes []PluginRuntimeDetails if err = mapstructure.Decode(secret.Data["runtimes"], &runtimes); err != nil { return nil, err } // return all runtimes in the catalog if input == nil { return &ListPluginRuntimesResponse{Runtimes: runtimes}, nil } result := &ListPluginRuntimesResponse{ Runtimes: []PluginRuntimeDetails{}, } for _, runtime := range runtimes { if runtime.Type == input.Type.String() { result.Runtimes = append(result.Runtimes, runtime) } } return result, nil } // pluginRuntimeCatalogPathByType is a helper to construct the proper API path by plugin type func pluginRuntimeCatalogPathByType(runtimeType PluginRuntimeType, name string) string { return fmt.Sprintf("/v1/sys/plugins/runtimes/catalog/%s/%s", runtimeType, name) } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_policy.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "errors" "fmt" "net/http" "github.com/mitchellh/mapstructure" ) func (c *Sys) ListPolicies() ([]string, error) { return c.ListPoliciesWithContext(context.Background()) } func (c *Sys) ListPoliciesWithContext(ctx context.Context) ([]string, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest("LIST", "/v1/sys/policies/acl") // Set this for broader compatibility, but we use LIST above to be able to // handle the wrapping lookup function r.Method = http.MethodGet r.Params.Set("list", "true") resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } var result []string err = mapstructure.Decode(secret.Data["keys"], &result) if err != nil { return nil, err } return result, err } func (c *Sys) GetPolicy(name string) (string, error) { return c.GetPolicyWithContext(context.Background(), name) } func (c *Sys) GetPolicyWithContext(ctx context.Context, name string) (string, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, fmt.Sprintf("/v1/sys/policies/acl/%s", name)) resp, err := c.c.rawRequestWithContext(ctx, r) if resp != nil { defer resp.Body.Close() if resp.StatusCode == 404 { return "", nil } } if err != nil { return "", err } secret, err := ParseSecret(resp.Body) if err != nil { return "", err } if secret == nil || secret.Data == nil { return "", errors.New("data from server response is empty") } if policyRaw, ok := secret.Data["policy"]; ok { return policyRaw.(string), nil } return "", fmt.Errorf("no policy found in response") } func (c *Sys) PutPolicy(name, rules string) error { return c.PutPolicyWithContext(context.Background(), name, rules) } func (c *Sys) PutPolicyWithContext(ctx context.Context, name, rules string) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() body := map[string]string{ "policy": rules, } r := c.c.NewRequest(http.MethodPut, fmt.Sprintf("/v1/sys/policies/acl/%s", name)) if err := r.SetJSONBody(body); err != nil { return err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return err } defer resp.Body.Close() return nil } func (c *Sys) DeletePolicy(name string) error { return c.DeletePolicyWithContext(context.Background(), name) } func (c *Sys) DeletePolicyWithContext(ctx context.Context, name string) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodDelete, fmt.Sprintf("/v1/sys/policies/acl/%s", name)) resp, err := c.c.rawRequestWithContext(ctx, r) if err == nil { defer resp.Body.Close() } return err } type getPoliciesResp struct { Rules string `json:"rules"` } type listPoliciesResp struct { Policies []string `json:"policies"` } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_raft.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "archive/tar" "compress/gzip" "context" "encoding/json" "errors" "fmt" "io" "io/ioutil" "net/http" "net/url" "sync" "time" "github.com/hashicorp/go-secure-stdlib/parseutil" "github.com/mitchellh/mapstructure" ) var ErrIncompleteSnapshot = errors.New("incomplete snapshot, unable to read SHA256SUMS.sealed file") // RaftJoinResponse represents the response of the raft join API type RaftJoinResponse struct { Joined bool `json:"joined"` } // RaftJoinRequest represents the parameters consumed by the raft join API type RaftJoinRequest struct { AutoJoin string `json:"auto_join"` AutoJoinScheme string `json:"auto_join_scheme"` AutoJoinPort uint `json:"auto_join_port"` LeaderAPIAddr string `json:"leader_api_addr"` LeaderCACert string `json:"leader_ca_cert"` LeaderClientCert string `json:"leader_client_cert"` LeaderClientKey string `json:"leader_client_key"` Retry bool `json:"retry"` NonVoter bool `json:"non_voter"` } // AutopilotConfig is used for querying/setting the Autopilot configuration. type AutopilotConfig struct { CleanupDeadServers bool `json:"cleanup_dead_servers" mapstructure:"cleanup_dead_servers"` LastContactThreshold time.Duration `json:"last_contact_threshold" mapstructure:"-"` DeadServerLastContactThreshold time.Duration `json:"dead_server_last_contact_threshold" mapstructure:"-"` MaxTrailingLogs uint64 `json:"max_trailing_logs" mapstructure:"max_trailing_logs"` MinQuorum uint `json:"min_quorum" mapstructure:"min_quorum"` ServerStabilizationTime time.Duration `json:"server_stabilization_time" mapstructure:"-"` DisableUpgradeMigration bool `json:"disable_upgrade_migration" mapstructure:"disable_upgrade_migration"` } // MarshalJSON makes the autopilot config fields JSON compatible func (ac *AutopilotConfig) MarshalJSON() ([]byte, error) { return json.Marshal(map[string]interface{}{ "cleanup_dead_servers": ac.CleanupDeadServers, "last_contact_threshold": ac.LastContactThreshold.String(), "dead_server_last_contact_threshold": ac.DeadServerLastContactThreshold.String(), "max_trailing_logs": ac.MaxTrailingLogs, "min_quorum": ac.MinQuorum, "server_stabilization_time": ac.ServerStabilizationTime.String(), "disable_upgrade_migration": ac.DisableUpgradeMigration, }) } // UnmarshalJSON parses the autopilot config JSON blob func (ac *AutopilotConfig) UnmarshalJSON(b []byte) error { var data interface{} err := json.Unmarshal(b, &data) if err != nil { return err } conf := data.(map[string]interface{}) if err = mapstructure.WeakDecode(conf, ac); err != nil { return err } if ac.LastContactThreshold, err = parseutil.ParseDurationSecond(conf["last_contact_threshold"]); err != nil { return err } if ac.DeadServerLastContactThreshold, err = parseutil.ParseDurationSecond(conf["dead_server_last_contact_threshold"]); err != nil { return err } if ac.ServerStabilizationTime, err = parseutil.ParseDurationSecond(conf["server_stabilization_time"]); err != nil { return err } return nil } // AutopilotState represents the response of the raft autopilot state API type AutopilotState struct { Healthy bool `mapstructure:"healthy"` FailureTolerance int `mapstructure:"failure_tolerance"` Servers map[string]*AutopilotServer `mapstructure:"servers"` Leader string `mapstructure:"leader"` Voters []string `mapstructure:"voters"` NonVoters []string `mapstructure:"non_voters"` RedundancyZones map[string]AutopilotZone `mapstructure:"redundancy_zones,omitempty"` Upgrade *AutopilotUpgrade `mapstructure:"upgrade_info,omitempty"` OptimisticFailureTolerance int `mapstructure:"optimistic_failure_tolerance,omitempty"` } func (a *AutopilotState) String() string { var result string result += fmt.Sprintf("Healthy: %t. FailureTolerance: %d. Leader: %s. OptimisticFailureTolerance: %d\n", a.Healthy, a.FailureTolerance, a.Leader, a.OptimisticFailureTolerance) for _, s := range a.Servers { result += fmt.Sprintf("Server: %s\n", s) } result += fmt.Sprintf("Voters: %v\n", a.Voters) result += fmt.Sprintf("NonVoters: %v\n", a.NonVoters) for name, zone := range a.RedundancyZones { result += fmt.Sprintf("RedundancyZone %s: %s\n", name, &zone) } result += fmt.Sprintf("Upgrade: %s", a.Upgrade) return result } // AutopilotServer represents the server blocks in the response of the raft // autopilot state API. type AutopilotServer struct { ID string `mapstructure:"id"` Name string `mapstructure:"name"` Address string `mapstructure:"address"` NodeStatus string `mapstructure:"node_status"` LastContact string `mapstructure:"last_contact"` LastTerm uint64 `mapstructure:"last_term"` LastIndex uint64 `mapstructure:"last_index"` Healthy bool `mapstructure:"healthy"` StableSince string `mapstructure:"stable_since"` Status string `mapstructure:"status"` Version string `mapstructure:"version"` UpgradeVersion string `mapstructure:"upgrade_version,omitempty"` RedundancyZone string `mapstructure:"redundancy_zone,omitempty"` NodeType string `mapstructure:"node_type,omitempty"` } func (a *AutopilotServer) String() string { return fmt.Sprintf("ID: %s. Name: %s. Address: %s. NodeStatus: %s. LastContact: %s. LastTerm: %d. LastIndex: %d. Healthy: %t. StableSince: %s. Status: %s. Version: %s. UpgradeVersion: %s. RedundancyZone: %s. NodeType: %s", a.ID, a.Name, a.Address, a.NodeStatus, a.LastContact, a.LastTerm, a.LastIndex, a.Healthy, a.StableSince, a.Status, a.Version, a.UpgradeVersion, a.RedundancyZone, a.NodeType) } type AutopilotZone struct { Servers []string `mapstructure:"servers,omitempty"` Voters []string `mapstructure:"voters,omitempty"` FailureTolerance int `mapstructure:"failure_tolerance,omitempty"` } func (a *AutopilotZone) String() string { return fmt.Sprintf("Servers: %v. Voters: %v. FailureTolerance: %d", a.Servers, a.Voters, a.FailureTolerance) } type AutopilotUpgrade struct { Status string `mapstructure:"status"` TargetVersion string `mapstructure:"target_version,omitempty"` TargetVersionVoters []string `mapstructure:"target_version_voters,omitempty"` TargetVersionNonVoters []string `mapstructure:"target_version_non_voters,omitempty"` TargetVersionReadReplicas []string `mapstructure:"target_version_read_replicas,omitempty"` OtherVersionVoters []string `mapstructure:"other_version_voters,omitempty"` OtherVersionNonVoters []string `mapstructure:"other_version_non_voters,omitempty"` OtherVersionReadReplicas []string `mapstructure:"other_version_read_replicas,omitempty"` RedundancyZones map[string]AutopilotZoneUpgradeVersions `mapstructure:"redundancy_zones,omitempty"` } func (a *AutopilotUpgrade) String() string { result := fmt.Sprintf("Status: %s. TargetVersion: %s. TargetVersionVoters: %v. TargetVersionNonVoters: %v. TargetVersionReadReplicas: %v. OtherVersionVoters: %v. OtherVersionNonVoters: %v. OtherVersionReadReplicas: %v", a.Status, a.TargetVersion, a.TargetVersionVoters, a.TargetVersionNonVoters, a.TargetVersionReadReplicas, a.OtherVersionVoters, a.OtherVersionNonVoters, a.OtherVersionReadReplicas) for name, zone := range a.RedundancyZones { result += fmt.Sprintf("Redundancy Zone %s: %s", name, zone) } return result } type AutopilotZoneUpgradeVersions struct { TargetVersionVoters []string `mapstructure:"target_version_voters,omitempty"` TargetVersionNonVoters []string `mapstructure:"target_version_non_voters,omitempty"` OtherVersionVoters []string `mapstructure:"other_version_voters,omitempty"` OtherVersionNonVoters []string `mapstructure:"other_version_non_voters,omitempty"` } func (a *AutopilotZoneUpgradeVersions) String() string { return fmt.Sprintf("TargetVersionVoters: %v. TargetVersionNonVoters: %v. OtherVersionVoters: %v. OtherVersionNonVoters: %v", a.TargetVersionVoters, a.TargetVersionNonVoters, a.OtherVersionVoters, a.OtherVersionNonVoters) } // RaftJoin wraps RaftJoinWithContext using context.Background. func (c *Sys) RaftJoin(opts *RaftJoinRequest) (*RaftJoinResponse, error) { return c.RaftJoinWithContext(context.Background(), opts) } // RaftJoinWithContext adds the node from which this call is invoked from to the raft // cluster represented by the leader address in the parameter. func (c *Sys) RaftJoinWithContext(ctx context.Context, opts *RaftJoinRequest) (*RaftJoinResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPost, "/v1/sys/storage/raft/join") if err := r.SetJSONBody(opts); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() var result RaftJoinResponse err = resp.DecodeJSON(&result) return &result, err } // RaftSnapshot wraps RaftSnapshotWithContext using context.Background. func (c *Sys) RaftSnapshot(snapWriter io.Writer) error { return c.RaftSnapshotWithContext(context.Background(), snapWriter) } // RaftSnapshotWithContext invokes the API that takes the snapshot of the raft cluster and // writes it to the supplied io.Writer. func (c *Sys) RaftSnapshotWithContext(ctx context.Context, snapWriter io.Writer) error { r := c.c.NewRequest(http.MethodGet, "/v1/sys/storage/raft/snapshot") r.URL.RawQuery = r.Params.Encode() resp, err := c.c.httpRequestWithContext(ctx, r) if err != nil { return err } defer resp.Body.Close() // Make sure that the last file in the archive, SHA256SUMS.sealed, is present // and non-empty. This is to catch cases where the snapshot failed midstream, // e.g. due to a problem with the seal that prevented encryption of that file. var wg sync.WaitGroup wg.Add(1) var verified bool rPipe, wPipe := io.Pipe() dup := io.TeeReader(resp.Body, wPipe) go func() { defer func() { io.Copy(ioutil.Discard, rPipe) rPipe.Close() wg.Done() }() uncompressed, err := gzip.NewReader(rPipe) if err != nil { return } t := tar.NewReader(uncompressed) var h *tar.Header for { h, err = t.Next() if err != nil { return } if h.Name != "SHA256SUMS.sealed" { continue } var b []byte b, err = io.ReadAll(t) if err != nil || len(b) == 0 { return } verified = true return } }() // Copy bytes from dup to snapWriter. This will have a side effect that // everything read from dup will be written to wPipe. _, err = io.Copy(snapWriter, dup) wPipe.Close() if err != nil { rPipe.CloseWithError(err) return err } wg.Wait() if !verified { return ErrIncompleteSnapshot } return nil } // RaftSnapshotRestore wraps RaftSnapshotRestoreWithContext using context.Background. func (c *Sys) RaftSnapshotRestore(snapReader io.Reader, force bool) error { return c.RaftSnapshotRestoreWithContext(context.Background(), snapReader, force) } // RaftSnapshotRestoreWithContext reads the snapshot from the io.Reader and installs that // snapshot, returning the cluster to the state defined by it. func (c *Sys) RaftSnapshotRestoreWithContext(ctx context.Context, snapReader io.Reader, force bool) error { path := "/v1/sys/storage/raft/snapshot" if force { path = "/v1/sys/storage/raft/snapshot-force" } r := c.c.NewRequest(http.MethodPost, path) r.Body = snapReader resp, err := c.c.httpRequestWithContext(ctx, r) if err != nil { return err } defer resp.Body.Close() return nil } // RaftAutopilotState wraps RaftAutopilotStateWithContext using context.Background. func (c *Sys) RaftAutopilotState() (*AutopilotState, error) { return c.RaftAutopilotStateWithContext(context.Background()) } // RaftAutopilotStateWithToken wraps RaftAutopilotStateWithContext using the given token. func (c *Sys) RaftAutopilotStateWithDRToken(drToken string) (*AutopilotState, error) { return c.RaftAutopilotStateWithContext(context.WithValue(context.Background(), "dr-token", drToken)) } // RaftAutopilotStateWithContext returns the state of the raft cluster as seen by autopilot. func (c *Sys) RaftAutopilotStateWithContext(ctx context.Context) (*AutopilotState, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() if ctx.Value("dr-token") != nil { c.c.SetToken(ctx.Value("dr-token").(string)) } r := c.c.NewRequest(http.MethodGet, "/v1/sys/storage/raft/autopilot/state") resp, err := c.c.rawRequestWithContext(ctx, r) if resp != nil { defer resp.Body.Close() if resp.StatusCode == 404 { return nil, nil } } if err != nil { return nil, err } secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } var result AutopilotState err = mapstructure.Decode(secret.Data, &result) if err != nil { return nil, err } return &result, err } // RaftAutopilotConfiguration wraps RaftAutopilotConfigurationWithContext using context.Background. func (c *Sys) RaftAutopilotConfiguration() (*AutopilotConfig, error) { return c.RaftAutopilotConfigurationWithContext(context.Background()) } // RaftAutopilotConfigurationWithDRToken wraps RaftAutopilotConfigurationWithContext using the given token. func (c *Sys) RaftAutopilotConfigurationWithDRToken(drToken string) (*AutopilotConfig, error) { return c.RaftAutopilotConfigurationWithContext(context.WithValue(context.Background(), "dr-token", drToken)) } // RaftAutopilotConfigurationWithContext fetches the autopilot config. func (c *Sys) RaftAutopilotConfigurationWithContext(ctx context.Context) (*AutopilotConfig, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() if ctx.Value("dr-token") != nil { c.c.SetToken(ctx.Value("dr-token").(string)) } r := c.c.NewRequest(http.MethodGet, "/v1/sys/storage/raft/autopilot/configuration") resp, err := c.c.rawRequestWithContext(ctx, r) if resp != nil { defer resp.Body.Close() if resp.StatusCode == 404 { return nil, nil } } if err != nil { return nil, err } secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret == nil { return nil, errors.New("data from server response is empty") } var result AutopilotConfig if err = mapstructure.Decode(secret.Data, &result); err != nil { return nil, err } if result.LastContactThreshold, err = parseutil.ParseDurationSecond(secret.Data["last_contact_threshold"]); err != nil { return nil, err } if result.DeadServerLastContactThreshold, err = parseutil.ParseDurationSecond(secret.Data["dead_server_last_contact_threshold"]); err != nil { return nil, err } if result.ServerStabilizationTime, err = parseutil.ParseDurationSecond(secret.Data["server_stabilization_time"]); err != nil { return nil, err } return &result, err } // PutRaftAutopilotConfiguration wraps PutRaftAutopilotConfigurationWithContext using context.Background. func (c *Sys) PutRaftAutopilotConfiguration(opts *AutopilotConfig) error { return c.PutRaftAutopilotConfigurationWithContext(context.Background(), opts) } // PutRaftAutopilotConfigurationWithContext allows modifying the raft autopilot configuration func (c *Sys) PutRaftAutopilotConfigurationWithContext(ctx context.Context, opts *AutopilotConfig) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPost, "/v1/sys/storage/raft/autopilot/configuration") if err := r.SetJSONBody(opts); err != nil { return err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return err } defer resp.Body.Close() return nil } // RaftLoadLocalSnapshot wraps RaftLoadLocalSnapshotWithContext using context.Background. func (c *Sys) RaftLoadLocalSnapshot(snapReader io.Reader) (*Secret, error) { return c.RaftLoadLocalSnapshotWithContext(context.Background(), snapReader) } // RaftLoadLocalSnapshotWithContext loads a snapshot into the raft cluster. // It accepts a reader that reads the snapshot file data. func (c *Sys) RaftLoadLocalSnapshotWithContext(ctx context.Context, snapReader io.Reader) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPost, "/v1/sys/storage/raft/snapshot-load") r.Body = snapReader resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() return ParseSecret(resp.Body) } // RaftLoadCloudSnapshot wraps RaftLoadCloudSnapshotWithContext using context.Background. func (c *Sys) RaftLoadCloudSnapshot(name string, url *url.URL) (*Secret, error) { return c.RaftLoadCloudSnapshotWithContext(context.Background(), name, url) } // RaftLoadCloudSnapshotWithContext loads a snapshot from cloud storage into the raft cluster. // It accepts a name for the cloud auto snapshot configuration and a URL to the snapshot location in cloud storage. func (c *Sys) RaftLoadCloudSnapshotWithContext(ctx context.Context, name string, url *url.URL) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPost, "/v1/sys/storage/raft/snapshot-auto/snapshot-load/"+name) if err := r.SetJSONBody(map[string]interface{}{ "url": url.String(), }); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() return ParseSecret(resp.Body) } // RaftUnloadSnapshot wraps RaftUnloadSnapshotWithContext using context.Background. func (c *Sys) RaftUnloadSnapshot(snapID string) (*Secret, error) { return c.RaftUnloadSnapshotWithContext(context.Background(), snapID) } // RaftUnloadSnapshotWithContext unloads a snapshot from the raft cluster. // It accepts a snapshot ID to identify the snapshot to be unloaded. func (c *Sys) RaftUnloadSnapshotWithContext(ctx context.Context, snapID string) (*Secret, error) { return c.raftUnloadSnapshotWithContext(ctx, snapID, false) } // RaftForceUnloadSnapshot wraps RaftForceUnloadSnapshotWithContext using context.Background. func (c *Sys) RaftForceUnloadSnapshot(snapID string) (*Secret, error) { return c.RaftForceUnloadSnapshotWithContext(context.Background(), snapID) } // RaftForceUnloadSnapshotWithContext forcefully unloads the given snapshot func (c *Sys) RaftForceUnloadSnapshotWithContext(ctx context.Context, snapID string) (*Secret, error) { return c.raftUnloadSnapshotWithContext(ctx, snapID, true) } func (c *Sys) raftUnloadSnapshotWithContext(ctx context.Context, snapID string, force bool) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodDelete, "/v1/sys/storage/raft/snapshot-load/"+snapID) if force { r.Params.Set("force", "true") } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() return ParseSecret(resp.Body) } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_rekey.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "errors" "net/http" "github.com/mitchellh/mapstructure" ) func (c *Sys) RekeyStatus() (*RekeyStatusResponse, error) { return c.RekeyStatusWithContext(context.Background()) } func (c *Sys) RekeyStatusWithContext(ctx context.Context) (*RekeyStatusResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, "/v1/sys/rekey/init") resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() var result RekeyStatusResponse err = resp.DecodeJSON(&result) return &result, err } func (c *Sys) RekeyRecoveryKeyStatus() (*RekeyStatusResponse, error) { return c.RekeyRecoveryKeyStatusWithContext(context.Background()) } func (c *Sys) RekeyRecoveryKeyStatusWithContext(ctx context.Context) (*RekeyStatusResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, "/v1/sys/rekey-recovery-key/init") resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() var result RekeyStatusResponse err = resp.DecodeJSON(&result) return &result, err } func (c *Sys) RekeyVerificationStatus() (*RekeyVerificationStatusResponse, error) { return c.RekeyVerificationStatusWithContext(context.Background()) } func (c *Sys) RekeyVerificationStatusWithContext(ctx context.Context) (*RekeyVerificationStatusResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, "/v1/sys/rekey/verify") resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() var result RekeyVerificationStatusResponse err = resp.DecodeJSON(&result) return &result, err } func (c *Sys) RekeyRecoveryKeyVerificationStatus() (*RekeyVerificationStatusResponse, error) { return c.RekeyRecoveryKeyVerificationStatusWithContext(context.Background()) } func (c *Sys) RekeyRecoveryKeyVerificationStatusWithContext(ctx context.Context) (*RekeyVerificationStatusResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, "/v1/sys/rekey-recovery-key/verify") resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() var result RekeyVerificationStatusResponse err = resp.DecodeJSON(&result) return &result, err } func (c *Sys) RekeyInit(config *RekeyInitRequest) (*RekeyStatusResponse, error) { return c.RekeyInitWithContext(context.Background(), config) } func (c *Sys) RekeyInitWithContext(ctx context.Context, config *RekeyInitRequest) (*RekeyStatusResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPut, "/v1/sys/rekey/init") if err := r.SetJSONBody(config); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() var result RekeyStatusResponse err = resp.DecodeJSON(&result) return &result, err } func (c *Sys) RekeyRecoveryKeyInit(config *RekeyInitRequest) (*RekeyStatusResponse, error) { return c.RekeyRecoveryKeyInitWithContext(context.Background(), config) } func (c *Sys) RekeyRecoveryKeyInitWithContext(ctx context.Context, config *RekeyInitRequest) (*RekeyStatusResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPut, "/v1/sys/rekey-recovery-key/init") if err := r.SetJSONBody(config); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() var result RekeyStatusResponse err = resp.DecodeJSON(&result) return &result, err } func (c *Sys) RekeyCancel() error { return c.RekeyCancelWithContext(context.Background()) } func (c *Sys) RekeyCancelWithNonce(nonce string) error { return c.RekeyCancelWithContextWithNonce(context.Background(), nonce) } func (c *Sys) RekeyCancelWithContext(ctx context.Context) error { return c.RekeyCancelWithContextWithNonce(ctx, "") } func (c *Sys) RekeyCancelWithContextWithNonce(ctx context.Context, nonce string) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodDelete, "/v1/sys/rekey/init") if nonce != "" { body := map[string]interface{}{ "nonce": nonce, } if err := r.SetJSONBody(body); err != nil { return err } } resp, err := c.c.rawRequestWithContext(ctx, r) if err == nil { defer resp.Body.Close() } return err } func (c *Sys) RekeyRecoveryKeyCancel() error { return c.RekeyRecoveryKeyCancelWithContext(context.Background()) } func (c *Sys) RekeyRecoveryKeyCancelWithNonce(nonce string) error { return c.RekeyRecoveryKeyCancelWithContextWithNonce(context.Background(), nonce) } func (c *Sys) RekeyRecoveryKeyCancelWithContext(ctx context.Context) error { return c.RekeyCancelWithContextWithNonce(ctx, "") } func (c *Sys) RekeyRecoveryKeyCancelWithContextWithNonce(ctx context.Context, nonce string) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodDelete, "/v1/sys/rekey-recovery-key/init") if nonce != "" { body := map[string]interface{}{ "nonce": nonce, } if err := r.SetJSONBody(body); err != nil { return err } } resp, err := c.c.rawRequestWithContext(ctx, r) if err == nil { defer resp.Body.Close() } return err } func (c *Sys) RekeyVerificationCancel() error { return c.RekeyVerificationCancelWithContext(context.Background()) } func (c *Sys) RekeyVerificationCancelWithContext(ctx context.Context) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodDelete, "/v1/sys/rekey/verify") resp, err := c.c.rawRequestWithContext(ctx, r) if err == nil { defer resp.Body.Close() } return err } func (c *Sys) RekeyRecoveryKeyVerificationCancel() error { return c.RekeyRecoveryKeyVerificationCancelWithContext(context.Background()) } func (c *Sys) RekeyRecoveryKeyVerificationCancelWithContext(ctx context.Context) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodDelete, "/v1/sys/rekey-recovery-key/verify") resp, err := c.c.rawRequestWithContext(ctx, r) if err == nil { defer resp.Body.Close() } return err } func (c *Sys) RekeyUpdate(shard, nonce string) (*RekeyUpdateResponse, error) { return c.RekeyUpdateWithContext(context.Background(), shard, nonce) } func (c *Sys) RekeyUpdateWithContext(ctx context.Context, shard, nonce string) (*RekeyUpdateResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() body := map[string]interface{}{ "key": shard, "nonce": nonce, } r := c.c.NewRequest(http.MethodPut, "/v1/sys/rekey/update") if err := r.SetJSONBody(body); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() var result RekeyUpdateResponse err = resp.DecodeJSON(&result) return &result, err } func (c *Sys) RekeyRecoveryKeyUpdate(shard, nonce string) (*RekeyUpdateResponse, error) { return c.RekeyRecoveryKeyUpdateWithContext(context.Background(), shard, nonce) } func (c *Sys) RekeyRecoveryKeyUpdateWithContext(ctx context.Context, shard, nonce string) (*RekeyUpdateResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() body := map[string]interface{}{ "key": shard, "nonce": nonce, } r := c.c.NewRequest(http.MethodPut, "/v1/sys/rekey-recovery-key/update") if err := r.SetJSONBody(body); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() var result RekeyUpdateResponse err = resp.DecodeJSON(&result) return &result, err } func (c *Sys) RekeyRetrieveBackup() (*RekeyRetrieveResponse, error) { return c.RekeyRetrieveBackupWithContext(context.Background()) } func (c *Sys) RekeyRetrieveBackupWithContext(ctx context.Context) (*RekeyRetrieveResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, "/v1/sys/rekey/backup") resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } var result RekeyRetrieveResponse err = mapstructure.Decode(secret.Data, &result) if err != nil { return nil, err } return &result, err } func (c *Sys) RekeyRetrieveRecoveryBackup() (*RekeyRetrieveResponse, error) { return c.RekeyRetrieveRecoveryBackupWithContext(context.Background()) } func (c *Sys) RekeyRetrieveRecoveryBackupWithContext(ctx context.Context) (*RekeyRetrieveResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, "/v1/sys/rekey/recovery-key-backup") resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } var result RekeyRetrieveResponse err = mapstructure.Decode(secret.Data, &result) if err != nil { return nil, err } return &result, err } func (c *Sys) RekeyDeleteBackup() error { return c.RekeyDeleteBackupWithContext(context.Background()) } func (c *Sys) RekeyDeleteBackupWithContext(ctx context.Context) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodDelete, "/v1/sys/rekey/backup") resp, err := c.c.rawRequestWithContext(ctx, r) if err == nil { defer resp.Body.Close() } return err } func (c *Sys) RekeyDeleteRecoveryBackup() error { return c.RekeyDeleteRecoveryBackupWithContext(context.Background()) } func (c *Sys) RekeyDeleteRecoveryBackupWithContext(ctx context.Context) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodDelete, "/v1/sys/rekey/recovery-key-backup") resp, err := c.c.rawRequestWithContext(ctx, r) if err == nil { defer resp.Body.Close() } return err } func (c *Sys) RekeyVerificationUpdate(shard, nonce string) (*RekeyVerificationUpdateResponse, error) { return c.RekeyVerificationUpdateWithContext(context.Background(), shard, nonce) } func (c *Sys) RekeyVerificationUpdateWithContext(ctx context.Context, shard, nonce string) (*RekeyVerificationUpdateResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() body := map[string]interface{}{ "key": shard, "nonce": nonce, } r := c.c.NewRequest(http.MethodPut, "/v1/sys/rekey/verify") if err := r.SetJSONBody(body); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() var result RekeyVerificationUpdateResponse err = resp.DecodeJSON(&result) return &result, err } func (c *Sys) RekeyRecoveryKeyVerificationUpdate(shard, nonce string) (*RekeyVerificationUpdateResponse, error) { return c.RekeyRecoveryKeyVerificationUpdateWithContext(context.Background(), shard, nonce) } func (c *Sys) RekeyRecoveryKeyVerificationUpdateWithContext(ctx context.Context, shard, nonce string) (*RekeyVerificationUpdateResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() body := map[string]interface{}{ "key": shard, "nonce": nonce, } r := c.c.NewRequest(http.MethodPut, "/v1/sys/rekey-recovery-key/verify") if err := r.SetJSONBody(body); err != nil { return nil, err } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() var result RekeyVerificationUpdateResponse err = resp.DecodeJSON(&result) return &result, err } type RekeyInitRequest struct { SecretShares int `json:"secret_shares"` SecretThreshold int `json:"secret_threshold"` StoredShares int `json:"stored_shares"` PGPKeys []string `json:"pgp_keys"` Backup bool RequireVerification bool `json:"require_verification"` } type RekeyStatusResponse struct { Nonce string `json:"nonce"` Started bool `json:"started"` T int `json:"t"` N int `json:"n"` Progress int `json:"progress"` Required int `json:"required"` PGPFingerprints []string `json:"pgp_fingerprints"` Backup bool `json:"backup"` VerificationRequired bool `json:"verification_required"` VerificationNonce string `json:"verification_nonce"` } type RekeyUpdateResponse struct { Nonce string `json:"nonce"` Complete bool `json:"complete"` Keys []string `json:"keys"` KeysB64 []string `json:"keys_base64"` PGPFingerprints []string `json:"pgp_fingerprints"` Backup bool `json:"backup"` VerificationRequired bool `json:"verification_required"` VerificationNonce string `json:"verification_nonce,omitempty"` } type RekeyRetrieveResponse struct { Nonce string `json:"nonce" mapstructure:"nonce"` Keys map[string][]string `json:"keys" mapstructure:"keys"` KeysB64 map[string][]string `json:"keys_base64" mapstructure:"keys_base64"` } type RekeyVerificationStatusResponse struct { Nonce string `json:"nonce"` Started bool `json:"started"` T int `json:"t"` N int `json:"n"` Progress int `json:"progress"` } type RekeyVerificationUpdateResponse struct { Nonce string `json:"nonce"` Complete bool `json:"complete"` } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_rotate.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "encoding/json" "errors" "net/http" "time" ) func (c *Sys) Rotate() error { return c.RotateWithContext(context.Background()) } func (c *Sys) RotateWithContext(ctx context.Context) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPost, "/v1/sys/rotate") resp, err := c.c.rawRequestWithContext(ctx, r) if err == nil { defer resp.Body.Close() } return err } func (c *Sys) KeyStatus() (*KeyStatus, error) { return c.KeyStatusWithContext(context.Background()) } func (c *Sys) KeyStatusWithContext(ctx context.Context) (*KeyStatus, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, "/v1/sys/key-status") resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } var result KeyStatus termRaw, ok := secret.Data["term"] if !ok { return nil, errors.New("term not found in response") } term, ok := termRaw.(json.Number) if !ok { return nil, errors.New("could not convert term to a number") } term64, err := term.Int64() if err != nil { return nil, err } result.Term = int(term64) installTimeRaw, ok := secret.Data["install_time"] if !ok { return nil, errors.New("install_time not found in response") } installTimeStr, ok := installTimeRaw.(string) if !ok { return nil, errors.New("could not convert install_time to a string") } installTime, err := time.Parse(time.RFC3339Nano, installTimeStr) if err != nil { return nil, err } result.InstallTime = installTime encryptionsRaw, ok := secret.Data["encryptions"] if ok { encryptions, ok := encryptionsRaw.(json.Number) if !ok { return nil, errors.New("could not convert encryptions to a number") } encryptions64, err := encryptions.Int64() if err != nil { return nil, err } result.Encryptions = int(encryptions64) } return &result, err } type KeyStatus struct { Term int `json:"term"` InstallTime time.Time `json:"install_time"` Encryptions int `json:"encryptions"` } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_seal.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "net/http" ) func (c *Sys) SealStatus() (*SealStatusResponse, error) { return c.SealStatusWithContext(context.Background()) } func (c *Sys) SealStatusWithContext(ctx context.Context) (*SealStatusResponse, error) { r := c.c.NewRequest(http.MethodGet, "/v1/sys/seal-status") return sealStatusRequestWithContext(ctx, c, r) } func (c *Sys) Seal() error { return c.SealWithContext(context.Background()) } func (c *Sys) SealWithContext(ctx context.Context) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPut, "/v1/sys/seal") resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return err } defer resp.Body.Close() return nil } func (c *Sys) ResetUnsealProcess() (*SealStatusResponse, error) { return c.ResetUnsealProcessWithContext(context.Background()) } func (c *Sys) ResetUnsealProcessWithContext(ctx context.Context) (*SealStatusResponse, error) { body := map[string]interface{}{"reset": true} r := c.c.NewRequest(http.MethodPut, "/v1/sys/unseal") if err := r.SetJSONBody(body); err != nil { return nil, err } return sealStatusRequestWithContext(ctx, c, r) } func (c *Sys) Unseal(shard string) (*SealStatusResponse, error) { return c.UnsealWithContext(context.Background(), shard) } func (c *Sys) UnsealWithContext(ctx context.Context, shard string) (*SealStatusResponse, error) { body := map[string]interface{}{"key": shard} r := c.c.NewRequest(http.MethodPut, "/v1/sys/unseal") if err := r.SetJSONBody(body); err != nil { return nil, err } return sealStatusRequestWithContext(ctx, c, r) } func (c *Sys) UnsealWithOptions(opts *UnsealOpts) (*SealStatusResponse, error) { return c.UnsealWithOptionsWithContext(context.Background(), opts) } func (c *Sys) UnsealWithOptionsWithContext(ctx context.Context, opts *UnsealOpts) (*SealStatusResponse, error) { r := c.c.NewRequest(http.MethodPut, "/v1/sys/unseal") if err := r.SetJSONBody(opts); err != nil { return nil, err } return sealStatusRequestWithContext(ctx, c, r) } func sealStatusRequestWithContext(ctx context.Context, c *Sys, r *Request) (*SealStatusResponse, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() var result SealStatusResponse err = resp.DecodeJSON(&result) return &result, err } type SealStatusResponse struct { Type string `json:"type"` Initialized bool `json:"initialized"` Sealed bool `json:"sealed"` T int `json:"t"` N int `json:"n"` Progress int `json:"progress"` Nonce string `json:"nonce"` Version string `json:"version"` BuildDate string `json:"build_date"` Migration bool `json:"migration"` ClusterName string `json:"cluster_name,omitempty"` ClusterID string `json:"cluster_id,omitempty"` RecoverySeal bool `json:"recovery_seal"` RecoverySealType string `json:"recovery_seal_type,omitempty"` StorageType string `json:"storage_type,omitempty"` HCPLinkStatus string `json:"hcp_link_status,omitempty"` HCPLinkResourceID string `json:"hcp_link_resource_ID,omitempty"` RemovedFromCluster *bool `json:"removed_from_cluster,omitempty"` Warnings []string `json:"warnings,omitempty"` } type UnsealOpts struct { Key string `json:"key"` Reset bool `json:"reset"` Migrate bool `json:"migrate"` } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_stepdown.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "net/http" ) func (c *Sys) StepDown() error { return c.StepDownWithContext(context.Background()) } func (c *Sys) StepDownWithContext(ctx context.Context) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPut, "/v1/sys/step-down") resp, err := c.c.rawRequestWithContext(ctx, r) if resp != nil && resp.Body != nil { resp.Body.Close() } return err } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_ui_custom_message.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "encoding/json" "errors" "fmt" "net/http" "strconv" ) const ( // baseEndpoint is the common base URL path for all endpoints used in this // module. baseEndpoint string = "/v1/sys/config/ui/custom-messages" ) // ListUICustomMessages calls ListUICustomMessagesWithContext using a background // Context. func (c *Sys) ListUICustomMessages(req UICustomMessageListRequest) (*Secret, error) { return c.ListUICustomMessagesWithContext(context.Background(), req) } // ListUICustomMessagesWithContext sends a request to the List custom messages // endpoint using the provided Context and UICustomMessageListRequest value as // the inputs. It returns a pointer to a Secret if a response was obtained from // the server, including error responses; or an error if a response could not be // obtained due to an error. func (c *Sys) ListUICustomMessagesWithContext(ctx context.Context, req UICustomMessageListRequest) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest("LIST", fmt.Sprintf("%s/", baseEndpoint)) if req.Active != nil { r.Params.Add("active", strconv.FormatBool(*req.Active)) } if req.Authenticated != nil { r.Params.Add("authenticated", strconv.FormatBool(*req.Authenticated)) } if req.Type != nil { r.Params.Add("type", *req.Type) } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } return secret, nil } // CreateUICustomMessage calls CreateUICustomMessageWithContext using a // background Context. func (c *Sys) CreateUICustomMessage(req UICustomMessageRequest) (*Secret, error) { return c.CreateUICustomMessageWithContext(context.Background(), req) } // CreateUICustomMessageWithContext sends a request to the Create custom // messages endpoint using the provided Context and UICustomMessageRequest // values as the inputs. It returns a pointer to a Secret if a response was // obtained from the server, including error responses; or an error if a // response could not be obtained due to an error. func (c *Sys) CreateUICustomMessageWithContext(ctx context.Context, req UICustomMessageRequest) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPost, baseEndpoint) if err := r.SetJSONBody(&req); err != nil { return nil, fmt.Errorf("error encoding request body to json: %w", err) } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, fmt.Errorf("error sending request to server: %w", err) } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, fmt.Errorf("could not parse secret from server response: %w", err) } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } return secret, nil } // ReadUICustomMessage calls ReadUICustomMessageWithContext using a background // Context. func (c *Sys) ReadUICustomMessage(id string) (*Secret, error) { return c.ReadUICustomMessageWithContext(context.Background(), id) } // ReadUICustomMessageWithContext sends a request to the Read custom message // endpoint using the provided Context and id values. It returns a pointer to a // Secret if a response was obtained from the server, including error responses; // or an error if a response could not be obtained due to an error. func (c *Sys) ReadUICustomMessageWithContext(ctx context.Context, id string) (*Secret, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, fmt.Sprintf("%s/%s", baseEndpoint, id)) resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, fmt.Errorf("error sending request to server: %w", err) } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, fmt.Errorf("could not parse secret from server response: %w", err) } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } return secret, nil } // UpdateUICustomMessage calls UpdateUICustomMessageWithContext using a // background Context. func (c *Sys) UpdateUICustomMessage(id string, req UICustomMessageRequest) error { return c.UpdateUICustomMessageWithContext(context.Background(), id, req) } // UpdateUICustomMessageWithContext sends a request to the Update custom message // endpoint using the provided Context, id, and UICustomMessageRequest values. // It returns a pointer to a Secret if a response was obtained from the server, // including error responses; or an error if a response could not be obtained // due to an error. func (c *Sys) UpdateUICustomMessageWithContext(ctx context.Context, id string, req UICustomMessageRequest) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodPost, fmt.Sprintf("%s/%s", baseEndpoint, id)) if err := r.SetJSONBody(&req); err != nil { return fmt.Errorf("error encoding request body to json: %w", err) } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return fmt.Errorf("error sending request to server: %w", err) } defer resp.Body.Close() return nil } // DeleteUICustomMessage calls DeleteUICustomMessageWithContext using a // background Context. func (c *Sys) DeleteUICustomMessage(id string) error { return c.DeletePolicyWithContext(context.Background(), id) } // DeleteUICustomMessageWithContext sends a request to the Delete custom message // endpoint using the provided Context and id values. It returns a pointer to a // Secret if a response was obtained from the server, including error responses; // or an error if a response could not be obtained due to an error. func (c *Sys) DeleteUICustomMessageWithContext(ctx context.Context, id string) error { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodDelete, fmt.Sprintf("%s/%s", baseEndpoint, id)) resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return fmt.Errorf("error sending request to server: %w", err) } defer resp.Body.Close() return nil } // UICustomMessageListRequest is a struct used to contain inputs for the List // custom messages request. Each field is optional, so their types are pointers. // The With... methods can be used to easily set the fields with pointers to // values. type UICustomMessageListRequest struct { Authenticated *bool Type *string Active *bool } // WithAuthenticated sets the Authenticated field to a pointer referencing the // provided bool value. func (r *UICustomMessageListRequest) WithAuthenticated(value bool) *UICustomMessageListRequest { r.Authenticated = &value return r } // WithType sets the Type field to a pointer referencing the provided string // value. func (r *UICustomMessageListRequest) WithType(value string) *UICustomMessageListRequest { r.Type = &value return r } // WithActive sets the Active field to a pointer referencing the provided bool // value. func (r *UICustomMessageListRequest) WithActive(value bool) *UICustomMessageListRequest { r.Active = &value return r } // UICustomMessageRequest is a struct containing the properties of a custom // message. The Link field can be set using the WithLink method. type UICustomMessageRequest struct { Title string `json:"title"` Message string `json:"message"` Authenticated bool `json:"authenticated"` Type string `json:"type"` StartTime string `json:"start_time"` EndTime string `json:"end_time,omitempty"` Link *uiCustomMessageLink `json:"link,omitempty"` Options map[string]any `json:"options,omitempty"` } // WithLink sets the Link field to the address of a new uiCustomMessageLink // struct constructed from the provided title and href values. func (r *UICustomMessageRequest) WithLink(title, href string) *UICustomMessageRequest { r.Link = &uiCustomMessageLink{ Title: title, Href: href, } return r } // uiCustomMessageLink is a utility struct used to represent a link associated // with a custom message. type uiCustomMessageLink struct { Title string Href string } // MarshalJSON encodes the state of the receiver uiCustomMessageLink as JSON and // returns those encoded bytes or an error. func (l uiCustomMessageLink) MarshalJSON() ([]byte, error) { m := make(map[string]string) m[l.Title] = l.Href return json.Marshal(m) } // UnmarshalJSON updates the state of the receiver uiCustomMessageLink from the // provided JSON encoded bytes. It returns an error if there was a failure. func (l *uiCustomMessageLink) UnmarshalJSON(b []byte) error { m := make(map[string]string) if err := json.Unmarshal(b, &m); err != nil { return err } for k, v := range m { l.Title = k l.Href = v break } return nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/sys_utilization_report.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package api import ( "context" "errors" "net/http" "github.com/mitchellh/mapstructure" ) func (c *Sys) UtilizationReport() (*UtilizationReportOutput, error) { return c.UtilizationReportWithContext(context.Background(), "") } func (c *Sys) UtilizationReportWithNamespace(nsPath string) (*UtilizationReportOutput, error) { return c.UtilizationReportWithContext(context.Background(), nsPath) } func (c *Sys) UtilizationReportWithContext(ctx context.Context, nsPath string) (*UtilizationReportOutput, error) { ctx, cancelFunc := c.c.withConfiguredTimeout(ctx) defer cancelFunc() r := c.c.NewRequest(http.MethodGet, "/v1/sys/utilization-report") if nsPath != "" { r.Params.Add("namespace", nsPath) } resp, err := c.c.rawRequestWithContext(ctx, r) if err != nil { return nil, err } defer resp.Body.Close() secret, err := ParseSecret(resp.Body) if err != nil { return nil, err } if secret == nil || secret.Data == nil { return nil, errors.New("data from server response is empty") } var result UtilizationReportOutput err = mapstructure.Decode(secret.Data, &result) if err != nil { return nil, err } return &result, err } type UtilizationReportOutput struct { Namespaces int `json:"namespaces,omitempty" structs:"namespaces" mapstructure:"namespaces"` KVV1Secrets int `json:"kvv1_secrets,omitempty" structs:"kvv1_secrets" mapstructure:"kvv1_secrets"` KVV2Secrets int `json:"kvv2_secrets,omitempty" structs:"kvv2_secrets" mapstructure:"kvv2_secrets"` AuthMethods map[string]int `json:"auth_methods,omitempty" structs:"auth_methods" mapstructure:"auth_methods"` SecretEngines map[string]int `json:"secret_engines,omitempty" structs:"secret_engines" mapstructure:"secret_engines"` LeasesByAuthMethod map[string]int `json:"leases_by_auth_method,omitempty" structs:"leases_by_auth_method" mapstructure:"leases_by_auth_method"` ReplicationStatus *UtilizationReportReplicationStatusInformation `json:"replication_status,omitempty" structs:"replication_status" mapstructure:"replication_status"` PKI *UtilizationReportPKIInformation `json:"pki,omitempty" structs:"pki" mapstructure:"pki"` SecretSync *UtilizationReportSecretSyncInformation `json:"secret_sync,omitempty" structs:"secret_sync" mapstructure:"secret_sync"` LeaseCountQuotas *UtilizationReportLeaseCountQuotaInformation `json:"lease_count_quotas,omitempty" structs:"lease_count_quotas" mapstructure:"lease_count_quotas"` } type UtilizationReportReplicationStatusInformation struct { DRPrimary bool `json:"dr_primary,omitempty" structs:"dr_primary" mapstructure:"dr_primary"` DRState string `json:"dr_state,omitempty" structs:"dr_state" mapstructure:"dr_state"` PRPrimary bool `json:"pr_primary,omitempty" structs:"pr_primary" mapstructure:"pr_primary"` PRState string `json:"pr_state,omitempty" structs:"pr_state" mapstructure:"pr_state"` } type UtilizationReportPKIInformation struct { TotalRoles int `json:"total_roles,omitempty" structs:"total_roles" mapstructure:"total_roles"` TotalIssuers int `json:"total_issuers,omitempty" structs:"total_issuers" mapstructure:"total_issuers"` } type UtilizationReportSecretSyncInformation struct { TotalSources int `json:"total_sources,omitempty" structs:"total_sources" mapstructure:"total_sources"` TotalDestinations int `json:"total_destinations,omitempty" structs:"total_destinations" mapstructure:"total_destinations"` } type UtilizationReportLeaseCountQuotaInformation struct { TotalLeaseCountQuotas int `json:"total_lease_count_quotas,omitempty" structs:"total_lease_count_quotas" mapstructure:"total_lease_count_quotas"` GlobalLeaseCountQuotaInformation *UtilizationReportGlobalLeaseCountQuotaInformation `json:"global_lease_count_quota,omitempty" structs:"global_lease_count_quota" mapstructure:"global_lease_count_quota"` } type UtilizationReportGlobalLeaseCountQuotaInformation struct { Name string `json:"name,omitempty" structs:"name" mapstructure:"name"` Capacity int `json:"capacity,omitempty" structs:"capacity" mapstructure:"capacity"` Count int `json:"count,omitempty" structs:"count" mapstructure:"count"` } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/tokenhelper/helper.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package tokenhelper // TokenHelper is an interface that contains basic operations that must be // implemented by a token helper type TokenHelper interface { // Path displays a method-specific path; for the internal helper this // is the location of the token stored on disk; for the external helper // this is the location of the binary being invoked Path() string Erase() error Get() (string, error) Store(string) error } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/tokenhelper/helper_external.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package tokenhelper import ( "bytes" "fmt" "os" "os/exec" "path/filepath" "strings" ) // ExternalTokenHelperPath should only be used in dev mode. // ExternalTokenHelperPath takes the configured path to a helper and expands it to // a full absolute path that can be executed. As of 0.5, the default token // helper is internal, to avoid problems running in dev mode (see GH-850 and // GH-783), so special assumptions of prepending "vault token-" no longer // apply. // // As an additional result, only absolute paths are now allowed. Looking in the // path or a current directory for an arbitrary executable could allow someone // to switch the expected binary for one further up the path (or in the current // directory), potentially opening up execution of an arbitrary binary. func ExternalTokenHelperPath(path string) (string, error) { if !filepath.IsAbs(path) { var err error path, err = filepath.Abs(path) if err != nil { return "", err } } if _, err := os.Stat(path); err != nil { return "", fmt.Errorf("unknown error getting the external helper path") } return path, nil } var _ TokenHelper = new(ExternalTokenHelper) // ExternalTokenHelper should only be used in a dev mode. For all other cases, // InternalTokenHelper should be used. // ExternalTokenHelper is the struct that has all the logic for storing and retrieving // tokens from the token helper. The API for the helpers is simple: the // BinaryPath is executed directly with arguments Args and environment Env. // The last argument appended to Args will be the operation, which is: // // - "get" - Read the value of the token and write it to stdout. // - "store" - Store the value of the token which is on stdin. Output // nothing. // - "erase" - Erase the contents stored. Output nothing. // // Any errors can be written on stdout. If the helper exits with a non-zero // exit code then the stderr will be made part of the error value. type ExternalTokenHelper struct { BinaryPath string Args []string Env []string } // Erase deletes the contents from the helper. func (h *ExternalTokenHelper) Erase() error { cmd, err := h.cmd("erase") if err != nil { return err } if output, err := cmd.CombinedOutput(); err != nil { return fmt.Errorf("%q: %w", string(output), err) } return nil } // Get gets the token value from the helper. func (h *ExternalTokenHelper) Get() (string, error) { var buf, stderr bytes.Buffer cmd, err := h.cmd("get") if err != nil { return "", err } cmd.Stdout = &buf cmd.Stderr = &stderr if err := cmd.Run(); err != nil { return "", fmt.Errorf("%q: %w", stderr.String(), err) } return buf.String(), nil } // Store stores the token value into the helper. func (h *ExternalTokenHelper) Store(v string) error { buf := bytes.NewBufferString(v) cmd, err := h.cmd("store") if err != nil { return err } cmd.Stdin = buf if output, err := cmd.CombinedOutput(); err != nil { return fmt.Errorf("%q: %w", string(output), err) } return nil } func (h *ExternalTokenHelper) Path() string { return h.BinaryPath } func (h *ExternalTokenHelper) cmd(op string) (*exec.Cmd, error) { binPath := strings.ReplaceAll(h.BinaryPath, "\\", "\\\\") args := make([]string, len(h.Args)) copy(args, h.Args) args = append(args, op) cmd := exec.Command(binPath, args...) cmd.Env = h.Env return cmd, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/tokenhelper/helper_internal.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package tokenhelper import ( "bytes" "fmt" "io" "os" "path/filepath" "strings" homedir "github.com/mitchellh/go-homedir" "github.com/natefinch/atomic" ) var _ TokenHelper = (*InternalTokenHelper)(nil) // InternalTokenHelper fulfills the TokenHelper interface when no external // token-helper is configured, and avoids shelling out type InternalTokenHelper struct { tokenPath string homeDir string } func NewInternalTokenHelper() (*InternalTokenHelper, error) { homeDir, err := homedir.Dir() if err != nil { panic(fmt.Sprintf("error getting user's home directory: %v", err)) } return &InternalTokenHelper{homeDir: homeDir}, err } // populateTokenPath figures out the token path using homedir to get the user's // home directory func (i *InternalTokenHelper) populateTokenPath() { i.tokenPath = filepath.Join(i.homeDir, ".vault-token") } func (i *InternalTokenHelper) Path() string { return i.tokenPath } // Get gets the value of the stored token, if any func (i *InternalTokenHelper) Get() (string, error) { i.populateTokenPath() f, err := os.Open(i.tokenPath) if os.IsNotExist(err) { return "", nil } if err != nil { return "", err } defer f.Close() buf := bytes.NewBuffer(nil) if _, err := io.Copy(buf, f); err != nil { return "", err } return strings.TrimSpace(buf.String()), nil } // Store stores the value of the token to the file. We always overwrite any // existing file atomically to ensure that ownership and permissions are set // appropriately. func (i *InternalTokenHelper) Store(input string) error { i.populateTokenPath() tmpFile := i.tokenPath + ".tmp" f, err := os.OpenFile(tmpFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0o600) if err != nil { return err } defer f.Close() defer os.Remove(tmpFile) _, err = io.WriteString(f, input) if err != nil { return err } err = f.Close() if err != nil { return err } // We don't care so much about atomic writes here. We're using this package // because we don't have a portable way of verifying that the target file // is owned by the correct user. The simplest way of ensuring that is // to simply re-write it, and the simplest way to ensure that we don't // damage an existing working file due to error is the write-rename pattern. // os.Rename on Windows will return an error if the target already exists. return atomic.ReplaceFile(tmpFile, i.tokenPath) } // Erase erases the value of the token func (i *InternalTokenHelper) Erase() error { i.populateTokenPath() if err := os.Remove(i.tokenPath); err != nil && !os.IsNotExist(err) { return err } return nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/hashicorp/vault/api/tokenhelper/testing.go ================================================ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 package tokenhelper import ( "testing" ) // test is a public function that can be used in other tests to // test that a helper is functioning properly. func test(t *testing.T, h TokenHelper) { if err := h.Store("foo"); err != nil { t.Fatalf("err: %s", err) } v, err := h.Get() if err != nil { t.Fatalf("err: %s", err) } if v != "foo" { t.Fatalf("bad: %#v", v) } if err := h.Erase(); err != nil { t.Fatalf("err: %s", err) } v, err = h.Get() if err != nil { t.Fatalf("err: %s", err) } if v != "" { t.Fatalf("bad: %#v", v) } } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/in-toto/attestation/go/v1/LICENSE ================================================ Copyright 2021 in-toto Developers 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/in-toto/in-toto-golang/in_toto/LICENSE ================================================ Copyright 2018 New York University 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/jedisct1/go-minisign/LICENSE ================================================ MIT License Copyright (c) 2018-2023 Frank Denis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/jellydator/ttlcache/v3/LICENSE ================================================ MIT License Copyright (c) 2022 Jellydator Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/json-iterator/go/LICENSE ================================================ MIT License Copyright (c) 2016 json-iterator Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/kelseyhightower/envconfig/LICENSE ================================================ Copyright (c) 2013 Kelsey Hightower Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/klauspost/compress/LICENSE ================================================ Copyright (c) 2012 The Go Authors. All rights reserved. Copyright (c) 2019 Klaus Post. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ------------------ Files: gzhttp/* Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2016-2017 The New York Times Company 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. ------------------ Files: s2/cmd/internal/readahead/* The MIT License (MIT) Copyright (c) 2015 Klaus Post Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------- Files: snappy/* Files: internal/snapref/* Copyright (c) 2011 The Snappy-Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------- Files: s2/cmd/internal/filepathx/* Copyright 2016 The filepathx Authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/klauspost/compress/internal/snapref/LICENSE ================================================ Copyright (c) 2011 The Snappy-Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/klauspost/compress/zstd/internal/xxhash/LICENSE.txt ================================================ Copyright (c) 2016 Caleb Spare MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/kylelemons/godebug/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/lestrrat-go/blackmagic/LICENSE ================================================ MIT License Copyright (c) 2021 lestrrat-go Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/lestrrat-go/dsig/LICENSE ================================================ MIT License Copyright (c) 2025 lestrrat-go Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/lestrrat-go/httpcc/LICENSE ================================================ MIT License Copyright (c) 2020 lestrrat-go Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/lestrrat-go/httprc/v3/LICENSE ================================================ MIT License Copyright (c) 2022 lestrrat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/lestrrat-go/jwx/v3/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2015 lestrrat Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/lestrrat-go/option/LICENSE ================================================ MIT License Copyright (c) 2021 lestrrat-go Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/lestrrat-go/option/v2/LICENSE ================================================ MIT License Copyright (c) 2021 lestrrat-go Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/letsencrypt/boulder/LICENSE.txt ================================================ Copyright 2016 ISRG. All rights reserved. Mozilla Public License Version 2.0 ================================== 1. Definitions -------------- 1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. 1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. 1.3. "Contribution" means Covered Software of a particular Contributor. 1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. 1.5. "Incompatible With Secondary Licenses" means (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. 1.6. "Executable Form" means any form of the work other than Source Code Form. 1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. 1.8. "License" means this document. 1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. 1.10. "Modifications" means any of the following: (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or (b) any new file in Source Code Form that contains any Covered Software. 1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. 1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. 1.13. "Source Code Form" means the form of the work preferred for making modifications. 1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. License Grants and Conditions -------------------------------- 2.1. Grants Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: (a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and (b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. 2.2. Effective Date The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. 2.3. Limitations on Grant Scope The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: (a) for any code that a Contributor has removed from Covered Software; or (b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or (c) under Patent Claims infringed by Covered Software in the absence of its Contributions. This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). 2.4. Subsequent Licenses No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). 2.5. Representation Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. 2.6. Fair Use This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. 2.7. Conditions Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. 3. Responsibilities ------------------- 3.1. Distribution of Source Form All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. 3.2. Distribution of Executable Form If You distribute Covered Software in Executable Form then: (a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and (b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. 3.3. Distribution of a Larger Work You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). 3.4. Notices You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. 3.5. Application of Additional Terms You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. 4. Inability to Comply Due to Statute or Regulation --------------------------------------------------- If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Termination -------------- 5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. 5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. ************************************************************************ * * * 6. Disclaimer of Warranty * * ------------------------- * * * * Covered Software is provided under this License on an "as is" * * basis, without warranty of any kind, either expressed, implied, or * * statutory, including, without limitation, warranties that the * * Covered Software is free of defects, merchantable, fit for a * * particular purpose or non-infringing. The entire risk as to the * * quality and performance of the Covered Software is with You. * * Should any Covered Software prove defective in any respect, You * * (not any Contributor) assume the cost of any necessary servicing, * * repair, or correction. This disclaimer of warranty constitutes an * * essential part of this License. No use of any Covered Software is * * authorized under this License except under this disclaimer. * * * ************************************************************************ ************************************************************************ * * * 7. Limitation of Liability * * -------------------------- * * * * Under no circumstances and under no legal theory, whether tort * * (including negligence), contract, or otherwise, shall any * * Contributor, or anyone who distributes Covered Software as * * permitted above, be liable to You for any direct, indirect, * * special, incidental, or consequential damages of any character * * including, without limitation, damages for lost profits, loss of * * goodwill, work stoppage, computer failure or malfunction, or any * * and all other commercial damages or losses, even if such party * * shall have been informed of the possibility of such damages. This * * limitation of liability shall not apply to liability for death or * * personal injury resulting from such party's negligence to the * * extent applicable law prohibits such limitation. Some * * jurisdictions do not allow the exclusion or limitation of * * incidental or consequential damages, so this exclusion and * * limitation may not apply to You. * * * ************************************************************************ 8. Litigation ------------- Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. 9. Miscellaneous ---------------- This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. 10. Versions of the License --------------------------- 10.1. New Versions Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. 10.2. Effect of New Versions You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. 10.3. Modified Versions If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). 10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. Exhibit A - Source Code Form License Notice ------------------------------------------- This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. You may add additional accurate notices of copyright ownership. Exhibit B - "Incompatible With Secondary Licenses" Notice --------------------------------------------------------- This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/letsencrypt/boulder/core/challenges.go ================================================ package core import "fmt" func newChallenge(challengeType AcmeChallenge, token string) Challenge { return Challenge{ Type: challengeType, Status: StatusPending, Token: token, } } // HTTPChallenge01 constructs a http-01 challenge. func HTTPChallenge01(token string) Challenge { return newChallenge(ChallengeTypeHTTP01, token) } // DNSChallenge01 constructs a dns-01 challenge. func DNSChallenge01(token string) Challenge { return newChallenge(ChallengeTypeDNS01, token) } // TLSALPNChallenge01 constructs a tls-alpn-01 challenge. func TLSALPNChallenge01(token string) Challenge { return newChallenge(ChallengeTypeTLSALPN01, token) } // DNSAccountChallenge01 constructs a dns-account-01 challenge. func DNSAccountChallenge01(token string) Challenge { return newChallenge(ChallengeTypeDNSAccount01, token) } // NewChallenge constructs a challenge of the given kind. It returns an // error if the challenge type is unrecognized. func NewChallenge(kind AcmeChallenge, token string) (Challenge, error) { switch kind { case ChallengeTypeHTTP01: return HTTPChallenge01(token), nil case ChallengeTypeDNS01: return DNSChallenge01(token), nil case ChallengeTypeTLSALPN01: return TLSALPNChallenge01(token), nil case ChallengeTypeDNSAccount01: return DNSAccountChallenge01(token), nil default: return Challenge{}, fmt.Errorf("unrecognized challenge type %q", kind) } } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/letsencrypt/boulder/core/interfaces.go ================================================ package core import ( "github.com/letsencrypt/boulder/identifier" ) // PolicyAuthority defines the public interface for the Boulder PA // TODO(#5891): Move this interface to a more appropriate location. type PolicyAuthority interface { WillingToIssue(identifier.ACMEIdentifiers) error ChallengeTypesFor(identifier.ACMEIdentifier) ([]AcmeChallenge, error) ChallengeTypeEnabled(AcmeChallenge) bool CheckAuthzChallenges(*Authorization) error } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/letsencrypt/boulder/core/objects.go ================================================ package core import ( "crypto" "encoding/base64" "encoding/json" "fmt" "hash/fnv" "net/netip" "strings" "time" "github.com/go-jose/go-jose/v4" "golang.org/x/crypto/ocsp" "github.com/letsencrypt/boulder/identifier" "github.com/letsencrypt/boulder/probs" "github.com/letsencrypt/boulder/revocation" ) // AcmeStatus defines the state of a given authorization type AcmeStatus string // These statuses are the states of authorizations, challenges, and registrations const ( StatusUnknown = AcmeStatus("unknown") // Unknown status; the default StatusPending = AcmeStatus("pending") // In process; client has next action StatusProcessing = AcmeStatus("processing") // In process; server has next action StatusReady = AcmeStatus("ready") // Order is ready for finalization StatusValid = AcmeStatus("valid") // Object is valid StatusInvalid = AcmeStatus("invalid") // Validation failed StatusRevoked = AcmeStatus("revoked") // Object no longer valid StatusDeactivated = AcmeStatus("deactivated") // Object has been deactivated ) // AcmeResource values identify different types of ACME resources type AcmeResource string // The types of ACME resources const ( ResourceNewReg = AcmeResource("new-reg") ResourceNewAuthz = AcmeResource("new-authz") ResourceNewCert = AcmeResource("new-cert") ResourceRevokeCert = AcmeResource("revoke-cert") ResourceRegistration = AcmeResource("reg") ResourceChallenge = AcmeResource("challenge") ResourceAuthz = AcmeResource("authz") ResourceKeyChange = AcmeResource("key-change") ) // AcmeChallenge values identify different types of ACME challenges type AcmeChallenge string // These types are the available challenges const ( ChallengeTypeHTTP01 = AcmeChallenge("http-01") ChallengeTypeDNS01 = AcmeChallenge("dns-01") ChallengeTypeTLSALPN01 = AcmeChallenge("tls-alpn-01") ChallengeTypeDNSAccount01 = AcmeChallenge("dns-account-01") ) // IsValid tests whether the challenge is a known challenge func (c AcmeChallenge) IsValid() bool { switch c { case ChallengeTypeHTTP01, ChallengeTypeDNS01, ChallengeTypeTLSALPN01, ChallengeTypeDNSAccount01: return true default: return false } } // OCSPStatus defines the state of OCSP for a certificate type OCSPStatus string // These status are the states of OCSP const ( OCSPStatusGood = OCSPStatus("good") OCSPStatusRevoked = OCSPStatus("revoked") ) var OCSPStatusToInt = map[OCSPStatus]int{ OCSPStatusGood: ocsp.Good, OCSPStatusRevoked: ocsp.Revoked, } // DNSPrefix is attached to DNS names in DNS challenges const DNSPrefix = "_acme-challenge" type RawCertificateRequest struct { CSR JSONBuffer `json:"csr"` // The encoded CSR } // Registration objects represent non-public metadata attached // to account keys. type Registration struct { // Unique identifier ID int64 `json:"-"` // Account key to which the details are attached Key *jose.JSONWebKey `json:"key"` // Contact URIs Contact *[]string `json:"contact,omitempty"` // Agreement with terms of service Agreement string `json:"-"` // CreatedAt is the time the registration was created. CreatedAt *time.Time `json:"createdAt,omitempty"` Status AcmeStatus `json:"status"` } // ValidationRecord represents a validation attempt against a specific URL/hostname // and the IP addresses that were resolved and used. type ValidationRecord struct { // SimpleHTTP only URL string `json:"url,omitempty"` // Shared // // Hostname can hold either a DNS name or an IP address. Hostname string `json:"hostname,omitempty"` Port string `json:"port,omitempty"` AddressesResolved []netip.Addr `json:"addressesResolved,omitempty"` AddressUsed netip.Addr `json:"addressUsed"` // AddressesTried contains a list of addresses tried before the `AddressUsed`. // Presently this will only ever be one IP from `AddressesResolved` since the // only retry is in the case of a v6 failure with one v4 fallback. E.g. if // a record with `AddressesResolved: { 127.0.0.1, ::1 }` were processed for // a challenge validation with the IPv6 first flag on and the ::1 address // failed but the 127.0.0.1 retry succeeded then the record would end up // being: // { // ... // AddressesResolved: [ 127.0.0.1, ::1 ], // AddressUsed: 127.0.0.1 // AddressesTried: [ ::1 ], // ... // } AddressesTried []netip.Addr `json:"addressesTried,omitempty"` // ResolverAddrs is the host:port of the DNS resolver(s) that fulfilled the // lookup for AddressUsed. During recursive A and AAAA lookups, a record may // instead look like A:host:port or AAAA:host:port ResolverAddrs []string `json:"resolverAddrs,omitempty"` } // Challenge is an aggregate of all data needed for any challenges. // // Rather than define individual types for different types of // challenge, we just throw all the elements into one bucket, // together with the common metadata elements. type Challenge struct { // Type is the type of challenge encoded in this object. Type AcmeChallenge `json:"type"` // URL is the URL to which a response can be posted. Required for all types. URL string `json:"url,omitempty"` // Status is the status of this challenge. Required for all types. Status AcmeStatus `json:"status,omitempty"` // Validated is the time at which the server validated the challenge. Required // if status is valid. Validated *time.Time `json:"validated,omitempty"` // Error contains the error that occurred during challenge validation, if any. // If set, the Status must be "invalid". Error *probs.ProblemDetails `json:"error,omitempty"` // Token is a random value that uniquely identifies the challenge. It is used // by all current challenges (http-01, tls-alpn-01, and dns-01). Token string `json:"token,omitempty"` // Contains information about URLs used or redirected to and IPs resolved and // used ValidationRecord []ValidationRecord `json:"validationRecord,omitempty"` } // ExpectedKeyAuthorization computes the expected KeyAuthorization value for // the challenge. func (ch Challenge) ExpectedKeyAuthorization(key *jose.JSONWebKey) (string, error) { if key == nil { return "", fmt.Errorf("Cannot authorize a nil key") } thumbprint, err := key.Thumbprint(crypto.SHA256) if err != nil { return "", err } return ch.Token + "." + base64.RawURLEncoding.EncodeToString(thumbprint), nil } // RecordsSane checks the sanity of a ValidationRecord object before sending it // back to the RA to be stored. func (ch Challenge) RecordsSane() bool { if len(ch.ValidationRecord) == 0 { return false } switch ch.Type { case ChallengeTypeHTTP01: for _, rec := range ch.ValidationRecord { // TODO(#7140): Add a check for ResolverAddress == "" only after the // core.proto change has been deployed. if rec.URL == "" || rec.Hostname == "" || rec.Port == "" || (rec.AddressUsed == netip.Addr{}) || len(rec.AddressesResolved) == 0 { return false } } case ChallengeTypeTLSALPN01: if len(ch.ValidationRecord) > 1 { return false } if ch.ValidationRecord[0].URL != "" { return false } // TODO(#7140): Add a check for ResolverAddress == "" only after the // core.proto change has been deployed. if ch.ValidationRecord[0].Hostname == "" || ch.ValidationRecord[0].Port == "" || (ch.ValidationRecord[0].AddressUsed == netip.Addr{}) || len(ch.ValidationRecord[0].AddressesResolved) == 0 { return false } case ChallengeTypeDNS01, ChallengeTypeDNSAccount01: if len(ch.ValidationRecord) > 1 { return false } // TODO(#7140): Add a check for ResolverAddress == "" only after the // core.proto change has been deployed. if ch.ValidationRecord[0].Hostname == "" { return false } return true default: // Unsupported challenge type return false } return true } // CheckPending ensures that a challenge object is pending and has a token. // This is used before offering the challenge to the client, and before actually // validating a challenge. func (ch Challenge) CheckPending() error { if ch.Status != StatusPending { return fmt.Errorf("challenge is not pending") } if !looksLikeAToken(ch.Token) { return fmt.Errorf("token is missing or malformed") } return nil } // StringID is used to generate a ID for challenges associated with new style authorizations. // This is necessary as these challenges no longer have a unique non-sequential identifier // in the new storage scheme. This identifier is generated by constructing a fnv hash over the // challenge token and type and encoding the first 4 bytes of it using the base64 URL encoding. func (ch Challenge) StringID() string { h := fnv.New128a() h.Write([]byte(ch.Token)) h.Write([]byte(ch.Type)) return base64.RawURLEncoding.EncodeToString(h.Sum(nil)[0:4]) } // Authorization represents the authorization of an account key holder to act on // behalf of an identifier. This struct is intended to be used both internally // and for JSON marshaling on the wire. Any fields that should be suppressed on // the wire (e.g., ID, regID) must be made empty before marshaling. type Authorization struct { // An identifier for this authorization, unique across // authorizations and certificates within this instance. ID string `json:"-"` // The identifier for which authorization is being given Identifier identifier.ACMEIdentifier `json:"identifier"` // The registration ID associated with the authorization RegistrationID int64 `json:"-"` // The status of the validation of this authorization Status AcmeStatus `json:"status,omitempty"` // The date after which this authorization will be no // longer be considered valid. Note: a certificate may be issued even on the // last day of an authorization's lifetime. The last day for which someone can // hold a valid certificate based on an authorization is authorization // lifetime + certificate lifetime. Expires *time.Time `json:"expires,omitempty"` // An array of challenges objects used to validate the // applicant's control of the identifier. For authorizations // in process, these are challenges to be fulfilled; for // final authorizations, they describe the evidence that // the server used in support of granting the authorization. // // There should only ever be one challenge of each type in this // slice and the order of these challenges may not be predictable. Challenges []Challenge `json:"challenges,omitempty"` // https://datatracker.ietf.org/doc/html/rfc8555#page-29 // // wildcard (optional, boolean): This field MUST be present and true // for authorizations created as a result of a newOrder request // containing a DNS identifier with a value that was a wildcard // domain name. For other authorizations, it MUST be absent. // Wildcard domain names are described in Section 7.1.3. // // This is not represented in the database because we calculate it from // the identifier stored in the database. Unlike the identifier returned // as part of the authorization, the identifier we store in the database // can contain an asterisk. Wildcard bool `json:"wildcard,omitempty"` // CertificateProfileName is the name of the profile associated with the // order that first resulted in the creation of this authorization. Omitted // from API responses. CertificateProfileName string `json:"-"` } // FindChallengeByStringID will look for a challenge matching the given ID inside // this authorization. If found, it will return the index of that challenge within // the Authorization's Challenges array. Otherwise it will return -1. func (authz *Authorization) FindChallengeByStringID(id string) int { for i, c := range authz.Challenges { if c.StringID() == id { return i } } return -1 } // SolvedBy will look through the Authorizations challenges, returning the type // of the *first* challenge it finds with Status: valid, or an error if no // challenge is valid. func (authz *Authorization) SolvedBy() (AcmeChallenge, error) { if len(authz.Challenges) == 0 { return "", fmt.Errorf("authorization has no challenges") } for _, chal := range authz.Challenges { if chal.Status == StatusValid { return chal.Type, nil } } return "", fmt.Errorf("authorization not solved by any challenge") } // JSONBuffer fields get encoded and decoded JOSE-style, in base64url encoding // with stripped padding. type JSONBuffer []byte // MarshalJSON encodes a JSONBuffer for transmission. func (jb JSONBuffer) MarshalJSON() (result []byte, err error) { return json.Marshal(base64.RawURLEncoding.EncodeToString(jb)) } // UnmarshalJSON decodes a JSONBuffer to an object. func (jb *JSONBuffer) UnmarshalJSON(data []byte) (err error) { var str string err = json.Unmarshal(data, &str) if err != nil { return err } *jb, err = base64.RawURLEncoding.DecodeString(strings.TrimRight(str, "=")) return } // Certificate objects are entirely internal to the server. The only // thing exposed on the wire is the certificate itself. type Certificate struct { ID int64 `db:"id"` RegistrationID int64 `db:"registrationID"` Serial string `db:"serial"` Digest string `db:"digest"` DER []byte `db:"der"` Issued time.Time `db:"issued"` Expires time.Time `db:"expires"` } // CertificateStatus structs are internal to the server. They represent the // latest data about the status of the certificate, required for generating new // OCSP responses and determining if a certificate has been revoked. type CertificateStatus struct { ID int64 `db:"id"` Serial string `db:"serial"` // status: 'good' or 'revoked'. Note that good, expired certificates remain // with status 'good' but don't necessarily get fresh OCSP responses. Status OCSPStatus `db:"status"` // ocspLastUpdated: The date and time of the last time we generated an OCSP // response. If we have never generated one, this has the zero value of // time.Time, i.e. Jan 1 1970. OCSPLastUpdated time.Time `db:"ocspLastUpdated"` // revokedDate: If status is 'revoked', this is the date and time it was // revoked. Otherwise it has the zero value of time.Time, i.e. Jan 1 1970. RevokedDate time.Time `db:"revokedDate"` // revokedReason: If status is 'revoked', this is the reason code for the // revocation. Otherwise it is zero (which happens to be the reason // code for 'unspecified'). RevokedReason revocation.Reason `db:"revokedReason"` LastExpirationNagSent time.Time `db:"lastExpirationNagSent"` // NotAfter and IsExpired are convenience columns which allow expensive // queries to quickly filter out certificates that we don't need to care // about anymore. These are particularly useful for the CRL updater. See // https://github.com/letsencrypt/boulder/issues/1864. NotAfter time.Time `db:"notAfter"` IsExpired bool `db:"isExpired"` // Note: this is not an issuance.IssuerNameID because that would create an // import cycle between core and issuance. // Note2: This field used to be called `issuerID`. We keep the old name in // the DB, but update the Go field name to be clear which type of ID this // is. IssuerNameID int64 `db:"issuerID"` } // SCTDERs is a convenience type type SCTDERs [][]byte // CertDER is a convenience type that helps differentiate what the // underlying byte slice contains type CertDER []byte // SuggestedWindow is a type exposed inside the RenewalInfo resource. type SuggestedWindow struct { Start time.Time `json:"start"` End time.Time `json:"end"` } // IsWithin returns true if the given time is within the suggested window, // inclusive of the start time and exclusive of the end time. func (window SuggestedWindow) IsWithin(now time.Time) bool { return !now.Before(window.Start) && now.Before(window.End) } // RenewalInfo is a type which is exposed to clients which query the renewalInfo // endpoint specified in draft-aaron-ari. type RenewalInfo struct { SuggestedWindow SuggestedWindow `json:"suggestedWindow"` ExplanationURL string `json:"explanationURL,omitempty"` } // RenewalInfoSimple constructs a `RenewalInfo` object and suggested window // using a very simple renewal calculation: calculate a point 2/3rds of the way // through the validity period (or halfway through, for short-lived certs), then // give a 2%-of-validity wide window around that. Both the `issued` and // `expires` timestamps are expected to be UTC. func RenewalInfoSimple(issued time.Time, expires time.Time) RenewalInfo { validity := expires.Add(time.Second).Sub(issued) renewalOffset := validity / time.Duration(3) if validity < 10*24*time.Hour { renewalOffset = validity / time.Duration(2) } idealRenewal := expires.Add(-renewalOffset) margin := validity / time.Duration(100) return RenewalInfo{ SuggestedWindow: SuggestedWindow{ Start: idealRenewal.Add(-1 * margin).Truncate(time.Second), End: idealRenewal.Add(margin).Truncate(time.Second), }, } } // RenewalInfoImmediate constructs a `RenewalInfo` object with a suggested // window in the past. Per the draft-ietf-acme-ari-01 spec, clients should // attempt to renew immediately if the suggested window is in the past. The // passed `now` is assumed to be a timestamp representing the current moment in // time. The `explanationURL` is an optional URL that the subscriber can use to // learn more about why the renewal is suggested. func RenewalInfoImmediate(now time.Time, explanationURL string) RenewalInfo { oneHourAgo := now.Add(-1 * time.Hour) return RenewalInfo{ SuggestedWindow: SuggestedWindow{ Start: oneHourAgo.Truncate(time.Second), End: oneHourAgo.Add(time.Minute * 30).Truncate(time.Second), }, ExplanationURL: explanationURL, } } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/letsencrypt/boulder/core/proto/core.pb.go ================================================ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.36.5 // protoc v3.20.1 // source: core.proto package proto import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" timestamppb "google.golang.org/protobuf/types/known/timestamppb" reflect "reflect" sync "sync" unsafe "unsafe" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) type Identifier struct { state protoimpl.MessageState `protogen:"open.v1"` Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *Identifier) Reset() { *x = Identifier{} mi := &file_core_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } func (x *Identifier) String() string { return protoimpl.X.MessageStringOf(x) } func (*Identifier) ProtoMessage() {} func (x *Identifier) ProtoReflect() protoreflect.Message { mi := &file_core_proto_msgTypes[0] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Identifier.ProtoReflect.Descriptor instead. func (*Identifier) Descriptor() ([]byte, []int) { return file_core_proto_rawDescGZIP(), []int{0} } func (x *Identifier) GetType() string { if x != nil { return x.Type } return "" } func (x *Identifier) GetValue() string { if x != nil { return x.Value } return "" } type Challenge struct { state protoimpl.MessageState `protogen:"open.v1"` Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` // Fields specified by RFC 8555, Section 8. Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` Url string `protobuf:"bytes,9,opt,name=url,proto3" json:"url,omitempty"` Status string `protobuf:"bytes,6,opt,name=status,proto3" json:"status,omitempty"` Validated *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=validated,proto3" json:"validated,omitempty"` Error *ProblemDetails `protobuf:"bytes,7,opt,name=error,proto3" json:"error,omitempty"` // Fields specified by individual validation methods. Token string `protobuf:"bytes,3,opt,name=token,proto3" json:"token,omitempty"` // Additional fields for our own record keeping. Validationrecords []*ValidationRecord `protobuf:"bytes,10,rep,name=validationrecords,proto3" json:"validationrecords,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *Challenge) Reset() { *x = Challenge{} mi := &file_core_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } func (x *Challenge) String() string { return protoimpl.X.MessageStringOf(x) } func (*Challenge) ProtoMessage() {} func (x *Challenge) ProtoReflect() protoreflect.Message { mi := &file_core_proto_msgTypes[1] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Challenge.ProtoReflect.Descriptor instead. func (*Challenge) Descriptor() ([]byte, []int) { return file_core_proto_rawDescGZIP(), []int{1} } func (x *Challenge) GetId() int64 { if x != nil { return x.Id } return 0 } func (x *Challenge) GetType() string { if x != nil { return x.Type } return "" } func (x *Challenge) GetUrl() string { if x != nil { return x.Url } return "" } func (x *Challenge) GetStatus() string { if x != nil { return x.Status } return "" } func (x *Challenge) GetValidated() *timestamppb.Timestamp { if x != nil { return x.Validated } return nil } func (x *Challenge) GetError() *ProblemDetails { if x != nil { return x.Error } return nil } func (x *Challenge) GetToken() string { if x != nil { return x.Token } return "" } func (x *Challenge) GetValidationrecords() []*ValidationRecord { if x != nil { return x.Validationrecords } return nil } type ValidationRecord struct { state protoimpl.MessageState `protogen:"open.v1"` // Next unused field number: 9 Hostname string `protobuf:"bytes,1,opt,name=hostname,proto3" json:"hostname,omitempty"` Port string `protobuf:"bytes,2,opt,name=port,proto3" json:"port,omitempty"` AddressesResolved [][]byte `protobuf:"bytes,3,rep,name=addressesResolved,proto3" json:"addressesResolved,omitempty"` // netip.Addr.MarshalText() AddressUsed []byte `protobuf:"bytes,4,opt,name=addressUsed,proto3" json:"addressUsed,omitempty"` // netip.Addr.MarshalText() Authorities []string `protobuf:"bytes,5,rep,name=authorities,proto3" json:"authorities,omitempty"` Url string `protobuf:"bytes,6,opt,name=url,proto3" json:"url,omitempty"` // A list of addresses tried before the address used (see // core/objects.go and the comment on the ValidationRecord structure // definition for more information. AddressesTried [][]byte `protobuf:"bytes,7,rep,name=addressesTried,proto3" json:"addressesTried,omitempty"` // netip.Addr.MarshalText() ResolverAddrs []string `protobuf:"bytes,8,rep,name=resolverAddrs,proto3" json:"resolverAddrs,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *ValidationRecord) Reset() { *x = ValidationRecord{} mi := &file_core_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } func (x *ValidationRecord) String() string { return protoimpl.X.MessageStringOf(x) } func (*ValidationRecord) ProtoMessage() {} func (x *ValidationRecord) ProtoReflect() protoreflect.Message { mi := &file_core_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use ValidationRecord.ProtoReflect.Descriptor instead. func (*ValidationRecord) Descriptor() ([]byte, []int) { return file_core_proto_rawDescGZIP(), []int{2} } func (x *ValidationRecord) GetHostname() string { if x != nil { return x.Hostname } return "" } func (x *ValidationRecord) GetPort() string { if x != nil { return x.Port } return "" } func (x *ValidationRecord) GetAddressesResolved() [][]byte { if x != nil { return x.AddressesResolved } return nil } func (x *ValidationRecord) GetAddressUsed() []byte { if x != nil { return x.AddressUsed } return nil } func (x *ValidationRecord) GetAuthorities() []string { if x != nil { return x.Authorities } return nil } func (x *ValidationRecord) GetUrl() string { if x != nil { return x.Url } return "" } func (x *ValidationRecord) GetAddressesTried() [][]byte { if x != nil { return x.AddressesTried } return nil } func (x *ValidationRecord) GetResolverAddrs() []string { if x != nil { return x.ResolverAddrs } return nil } type ProblemDetails struct { state protoimpl.MessageState `protogen:"open.v1"` ProblemType string `protobuf:"bytes,1,opt,name=problemType,proto3" json:"problemType,omitempty"` Detail string `protobuf:"bytes,2,opt,name=detail,proto3" json:"detail,omitempty"` HttpStatus int32 `protobuf:"varint,3,opt,name=httpStatus,proto3" json:"httpStatus,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *ProblemDetails) Reset() { *x = ProblemDetails{} mi := &file_core_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } func (x *ProblemDetails) String() string { return protoimpl.X.MessageStringOf(x) } func (*ProblemDetails) ProtoMessage() {} func (x *ProblemDetails) ProtoReflect() protoreflect.Message { mi := &file_core_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use ProblemDetails.ProtoReflect.Descriptor instead. func (*ProblemDetails) Descriptor() ([]byte, []int) { return file_core_proto_rawDescGZIP(), []int{3} } func (x *ProblemDetails) GetProblemType() string { if x != nil { return x.ProblemType } return "" } func (x *ProblemDetails) GetDetail() string { if x != nil { return x.Detail } return "" } func (x *ProblemDetails) GetHttpStatus() int32 { if x != nil { return x.HttpStatus } return 0 } type Certificate struct { state protoimpl.MessageState `protogen:"open.v1"` // Next unused field number: 9 RegistrationID int64 `protobuf:"varint,1,opt,name=registrationID,proto3" json:"registrationID,omitempty"` Serial string `protobuf:"bytes,2,opt,name=serial,proto3" json:"serial,omitempty"` Digest string `protobuf:"bytes,3,opt,name=digest,proto3" json:"digest,omitempty"` Der []byte `protobuf:"bytes,4,opt,name=der,proto3" json:"der,omitempty"` Issued *timestamppb.Timestamp `protobuf:"bytes,7,opt,name=issued,proto3" json:"issued,omitempty"` Expires *timestamppb.Timestamp `protobuf:"bytes,8,opt,name=expires,proto3" json:"expires,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *Certificate) Reset() { *x = Certificate{} mi := &file_core_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } func (x *Certificate) String() string { return protoimpl.X.MessageStringOf(x) } func (*Certificate) ProtoMessage() {} func (x *Certificate) ProtoReflect() protoreflect.Message { mi := &file_core_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Certificate.ProtoReflect.Descriptor instead. func (*Certificate) Descriptor() ([]byte, []int) { return file_core_proto_rawDescGZIP(), []int{4} } func (x *Certificate) GetRegistrationID() int64 { if x != nil { return x.RegistrationID } return 0 } func (x *Certificate) GetSerial() string { if x != nil { return x.Serial } return "" } func (x *Certificate) GetDigest() string { if x != nil { return x.Digest } return "" } func (x *Certificate) GetDer() []byte { if x != nil { return x.Der } return nil } func (x *Certificate) GetIssued() *timestamppb.Timestamp { if x != nil { return x.Issued } return nil } func (x *Certificate) GetExpires() *timestamppb.Timestamp { if x != nil { return x.Expires } return nil } type CertificateStatus struct { state protoimpl.MessageState `protogen:"open.v1"` // Next unused field number: 16 Serial string `protobuf:"bytes,1,opt,name=serial,proto3" json:"serial,omitempty"` Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` OcspLastUpdated *timestamppb.Timestamp `protobuf:"bytes,15,opt,name=ocspLastUpdated,proto3" json:"ocspLastUpdated,omitempty"` RevokedDate *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=revokedDate,proto3" json:"revokedDate,omitempty"` RevokedReason int64 `protobuf:"varint,6,opt,name=revokedReason,proto3" json:"revokedReason,omitempty"` LastExpirationNagSent *timestamppb.Timestamp `protobuf:"bytes,13,opt,name=lastExpirationNagSent,proto3" json:"lastExpirationNagSent,omitempty"` NotAfter *timestamppb.Timestamp `protobuf:"bytes,14,opt,name=notAfter,proto3" json:"notAfter,omitempty"` IsExpired bool `protobuf:"varint,10,opt,name=isExpired,proto3" json:"isExpired,omitempty"` IssuerID int64 `protobuf:"varint,11,opt,name=issuerID,proto3" json:"issuerID,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *CertificateStatus) Reset() { *x = CertificateStatus{} mi := &file_core_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } func (x *CertificateStatus) String() string { return protoimpl.X.MessageStringOf(x) } func (*CertificateStatus) ProtoMessage() {} func (x *CertificateStatus) ProtoReflect() protoreflect.Message { mi := &file_core_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use CertificateStatus.ProtoReflect.Descriptor instead. func (*CertificateStatus) Descriptor() ([]byte, []int) { return file_core_proto_rawDescGZIP(), []int{5} } func (x *CertificateStatus) GetSerial() string { if x != nil { return x.Serial } return "" } func (x *CertificateStatus) GetStatus() string { if x != nil { return x.Status } return "" } func (x *CertificateStatus) GetOcspLastUpdated() *timestamppb.Timestamp { if x != nil { return x.OcspLastUpdated } return nil } func (x *CertificateStatus) GetRevokedDate() *timestamppb.Timestamp { if x != nil { return x.RevokedDate } return nil } func (x *CertificateStatus) GetRevokedReason() int64 { if x != nil { return x.RevokedReason } return 0 } func (x *CertificateStatus) GetLastExpirationNagSent() *timestamppb.Timestamp { if x != nil { return x.LastExpirationNagSent } return nil } func (x *CertificateStatus) GetNotAfter() *timestamppb.Timestamp { if x != nil { return x.NotAfter } return nil } func (x *CertificateStatus) GetIsExpired() bool { if x != nil { return x.IsExpired } return false } func (x *CertificateStatus) GetIssuerID() int64 { if x != nil { return x.IssuerID } return 0 } type Registration struct { state protoimpl.MessageState `protogen:"open.v1"` // Next unused field number: 10 Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` Key []byte `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` Agreement string `protobuf:"bytes,5,opt,name=agreement,proto3" json:"agreement,omitempty"` CreatedAt *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=createdAt,proto3" json:"createdAt,omitempty"` Status string `protobuf:"bytes,8,opt,name=status,proto3" json:"status,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *Registration) Reset() { *x = Registration{} mi := &file_core_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } func (x *Registration) String() string { return protoimpl.X.MessageStringOf(x) } func (*Registration) ProtoMessage() {} func (x *Registration) ProtoReflect() protoreflect.Message { mi := &file_core_proto_msgTypes[6] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Registration.ProtoReflect.Descriptor instead. func (*Registration) Descriptor() ([]byte, []int) { return file_core_proto_rawDescGZIP(), []int{6} } func (x *Registration) GetId() int64 { if x != nil { return x.Id } return 0 } func (x *Registration) GetKey() []byte { if x != nil { return x.Key } return nil } func (x *Registration) GetAgreement() string { if x != nil { return x.Agreement } return "" } func (x *Registration) GetCreatedAt() *timestamppb.Timestamp { if x != nil { return x.CreatedAt } return nil } func (x *Registration) GetStatus() string { if x != nil { return x.Status } return "" } type Authorization struct { state protoimpl.MessageState `protogen:"open.v1"` Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` RegistrationID int64 `protobuf:"varint,3,opt,name=registrationID,proto3" json:"registrationID,omitempty"` Identifier *Identifier `protobuf:"bytes,11,opt,name=identifier,proto3" json:"identifier,omitempty"` Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"` Expires *timestamppb.Timestamp `protobuf:"bytes,9,opt,name=expires,proto3" json:"expires,omitempty"` Challenges []*Challenge `protobuf:"bytes,6,rep,name=challenges,proto3" json:"challenges,omitempty"` CertificateProfileName string `protobuf:"bytes,10,opt,name=certificateProfileName,proto3" json:"certificateProfileName,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *Authorization) Reset() { *x = Authorization{} mi := &file_core_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } func (x *Authorization) String() string { return protoimpl.X.MessageStringOf(x) } func (*Authorization) ProtoMessage() {} func (x *Authorization) ProtoReflect() protoreflect.Message { mi := &file_core_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Authorization.ProtoReflect.Descriptor instead. func (*Authorization) Descriptor() ([]byte, []int) { return file_core_proto_rawDescGZIP(), []int{7} } func (x *Authorization) GetId() string { if x != nil { return x.Id } return "" } func (x *Authorization) GetRegistrationID() int64 { if x != nil { return x.RegistrationID } return 0 } func (x *Authorization) GetIdentifier() *Identifier { if x != nil { return x.Identifier } return nil } func (x *Authorization) GetStatus() string { if x != nil { return x.Status } return "" } func (x *Authorization) GetExpires() *timestamppb.Timestamp { if x != nil { return x.Expires } return nil } func (x *Authorization) GetChallenges() []*Challenge { if x != nil { return x.Challenges } return nil } func (x *Authorization) GetCertificateProfileName() string { if x != nil { return x.CertificateProfileName } return "" } type Order struct { state protoimpl.MessageState `protogen:"open.v1"` Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` RegistrationID int64 `protobuf:"varint,2,opt,name=registrationID,proto3" json:"registrationID,omitempty"` // Fields specified by RFC 8555, Section 7.1.3 // Note that we do not respect notBefore and notAfter, and we infer the // finalize and certificate URLs from the id and certificateSerial fields. Status string `protobuf:"bytes,7,opt,name=status,proto3" json:"status,omitempty"` Expires *timestamppb.Timestamp `protobuf:"bytes,12,opt,name=expires,proto3" json:"expires,omitempty"` Identifiers []*Identifier `protobuf:"bytes,16,rep,name=identifiers,proto3" json:"identifiers,omitempty"` Error *ProblemDetails `protobuf:"bytes,4,opt,name=error,proto3" json:"error,omitempty"` V2Authorizations []int64 `protobuf:"varint,11,rep,packed,name=v2Authorizations,proto3" json:"v2Authorizations,omitempty"` CertificateSerial string `protobuf:"bytes,5,opt,name=certificateSerial,proto3" json:"certificateSerial,omitempty"` // Additional fields for our own record-keeping. Created *timestamppb.Timestamp `protobuf:"bytes,13,opt,name=created,proto3" json:"created,omitempty"` CertificateProfileName string `protobuf:"bytes,14,opt,name=certificateProfileName,proto3" json:"certificateProfileName,omitempty"` Replaces string `protobuf:"bytes,15,opt,name=replaces,proto3" json:"replaces,omitempty"` BeganProcessing bool `protobuf:"varint,9,opt,name=beganProcessing,proto3" json:"beganProcessing,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *Order) Reset() { *x = Order{} mi := &file_core_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } func (x *Order) String() string { return protoimpl.X.MessageStringOf(x) } func (*Order) ProtoMessage() {} func (x *Order) ProtoReflect() protoreflect.Message { mi := &file_core_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use Order.ProtoReflect.Descriptor instead. func (*Order) Descriptor() ([]byte, []int) { return file_core_proto_rawDescGZIP(), []int{8} } func (x *Order) GetId() int64 { if x != nil { return x.Id } return 0 } func (x *Order) GetRegistrationID() int64 { if x != nil { return x.RegistrationID } return 0 } func (x *Order) GetStatus() string { if x != nil { return x.Status } return "" } func (x *Order) GetExpires() *timestamppb.Timestamp { if x != nil { return x.Expires } return nil } func (x *Order) GetIdentifiers() []*Identifier { if x != nil { return x.Identifiers } return nil } func (x *Order) GetError() *ProblemDetails { if x != nil { return x.Error } return nil } func (x *Order) GetV2Authorizations() []int64 { if x != nil { return x.V2Authorizations } return nil } func (x *Order) GetCertificateSerial() string { if x != nil { return x.CertificateSerial } return "" } func (x *Order) GetCreated() *timestamppb.Timestamp { if x != nil { return x.Created } return nil } func (x *Order) GetCertificateProfileName() string { if x != nil { return x.CertificateProfileName } return "" } func (x *Order) GetReplaces() string { if x != nil { return x.Replaces } return "" } func (x *Order) GetBeganProcessing() bool { if x != nil { return x.BeganProcessing } return false } type CRLEntry struct { state protoimpl.MessageState `protogen:"open.v1"` // Next unused field number: 5 Serial string `protobuf:"bytes,1,opt,name=serial,proto3" json:"serial,omitempty"` Reason int32 `protobuf:"varint,2,opt,name=reason,proto3" json:"reason,omitempty"` RevokedAt *timestamppb.Timestamp `protobuf:"bytes,4,opt,name=revokedAt,proto3" json:"revokedAt,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *CRLEntry) Reset() { *x = CRLEntry{} mi := &file_core_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } func (x *CRLEntry) String() string { return protoimpl.X.MessageStringOf(x) } func (*CRLEntry) ProtoMessage() {} func (x *CRLEntry) ProtoReflect() protoreflect.Message { mi := &file_core_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use CRLEntry.ProtoReflect.Descriptor instead. func (*CRLEntry) Descriptor() ([]byte, []int) { return file_core_proto_rawDescGZIP(), []int{9} } func (x *CRLEntry) GetSerial() string { if x != nil { return x.Serial } return "" } func (x *CRLEntry) GetReason() int32 { if x != nil { return x.Reason } return 0 } func (x *CRLEntry) GetRevokedAt() *timestamppb.Timestamp { if x != nil { return x.RevokedAt } return nil } var File_core_proto protoreflect.FileDescriptor var file_core_proto_rawDesc = string([]byte{ 0x0a, 0x0a, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x63, 0x6f, 0x72, 0x65, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x36, 0x0a, 0x0a, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xb3, 0x02, 0x0a, 0x09, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x38, 0x0a, 0x09, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x62, 0x6c, 0x65, 0x6d, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x44, 0x0a, 0x11, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x52, 0x11, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x72, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x73, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, 0x04, 0x08, 0x0b, 0x10, 0x0c, 0x22, 0x94, 0x02, 0x0a, 0x10, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x2c, 0x0a, 0x11, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x64, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x11, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x73, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x55, 0x73, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x26, 0x0a, 0x0e, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x54, 0x72, 0x69, 0x65, 0x64, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0e, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x54, 0x72, 0x69, 0x65, 0x64, 0x12, 0x24, 0x0a, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0d, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x73, 0x22, 0x6a, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x62, 0x6c, 0x65, 0x6d, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x72, 0x6f, 0x62, 0x6c, 0x65, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x62, 0x6c, 0x65, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x68, 0x74, 0x74, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x68, 0x74, 0x74, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xed, 0x01, 0x0a, 0x0b, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x64, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x64, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x06, 0x69, 0x73, 0x73, 0x75, 0x65, 0x64, 0x12, 0x34, 0x0a, 0x07, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x22, 0xd5, 0x03, 0x0a, 0x11, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x44, 0x0a, 0x0f, 0x6f, 0x63, 0x73, 0x70, 0x4c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0f, 0x6f, 0x63, 0x73, 0x70, 0x4c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x3c, 0x0a, 0x0b, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0b, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, 0x12, 0x24, 0x0a, 0x0d, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x50, 0x0a, 0x15, 0x6c, 0x61, 0x73, 0x74, 0x45, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x67, 0x53, 0x65, 0x6e, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x15, 0x6c, 0x61, 0x73, 0x74, 0x45, 0x78, 0x70, 0x69, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4e, 0x61, 0x67, 0x53, 0x65, 0x6e, 0x74, 0x12, 0x36, 0x0a, 0x08, 0x6e, 0x6f, 0x74, 0x41, 0x66, 0x74, 0x65, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x08, 0x6e, 0x6f, 0x74, 0x41, 0x66, 0x74, 0x65, 0x72, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x73, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x69, 0x73, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x69, 0x73, 0x73, 0x75, 0x65, 0x72, 0x49, 0x44, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x22, 0xb8, 0x01, 0x0a, 0x0c, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x67, 0x72, 0x65, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x67, 0x72, 0x65, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x38, 0x0a, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x22, 0xc8, 0x02, 0x0a, 0x0d, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x30, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x34, 0x0a, 0x07, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x12, 0x2f, 0x0a, 0x0a, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x43, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x52, 0x0a, 0x63, 0x68, 0x61, 0x6c, 0x6c, 0x65, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x36, 0x0a, 0x16, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, 0x04, 0x08, 0x07, 0x10, 0x08, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x22, 0x93, 0x04, 0x0a, 0x05, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x26, 0x0a, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x34, 0x0a, 0x07, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x12, 0x32, 0x0a, 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x18, 0x10, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0b, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x73, 0x12, 0x2a, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6f, 0x72, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x62, 0x6c, 0x65, 0x6d, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x2a, 0x0a, 0x10, 0x76, 0x32, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x0b, 0x20, 0x03, 0x28, 0x03, 0x52, 0x10, 0x76, 0x32, 0x41, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x2c, 0x0a, 0x11, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x12, 0x34, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x12, 0x36, 0x0a, 0x16, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x16, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x62, 0x65, 0x67, 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x62, 0x65, 0x67, 0x61, 0x6e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x4a, 0x04, 0x08, 0x0a, 0x10, 0x0b, 0x4a, 0x04, 0x08, 0x08, 0x10, 0x09, 0x22, 0x7a, 0x0a, 0x08, 0x43, 0x52, 0x4c, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x38, 0x0a, 0x09, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x72, 0x65, 0x76, 0x6f, 0x6b, 0x65, 0x64, 0x41, 0x74, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x42, 0x2b, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x65, 0x74, 0x73, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x2f, 0x62, 0x6f, 0x75, 0x6c, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, }) var ( file_core_proto_rawDescOnce sync.Once file_core_proto_rawDescData []byte ) func file_core_proto_rawDescGZIP() []byte { file_core_proto_rawDescOnce.Do(func() { file_core_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_core_proto_rawDesc), len(file_core_proto_rawDesc))) }) return file_core_proto_rawDescData } var file_core_proto_msgTypes = make([]protoimpl.MessageInfo, 10) var file_core_proto_goTypes = []any{ (*Identifier)(nil), // 0: core.Identifier (*Challenge)(nil), // 1: core.Challenge (*ValidationRecord)(nil), // 2: core.ValidationRecord (*ProblemDetails)(nil), // 3: core.ProblemDetails (*Certificate)(nil), // 4: core.Certificate (*CertificateStatus)(nil), // 5: core.CertificateStatus (*Registration)(nil), // 6: core.Registration (*Authorization)(nil), // 7: core.Authorization (*Order)(nil), // 8: core.Order (*CRLEntry)(nil), // 9: core.CRLEntry (*timestamppb.Timestamp)(nil), // 10: google.protobuf.Timestamp } var file_core_proto_depIdxs = []int32{ 10, // 0: core.Challenge.validated:type_name -> google.protobuf.Timestamp 3, // 1: core.Challenge.error:type_name -> core.ProblemDetails 2, // 2: core.Challenge.validationrecords:type_name -> core.ValidationRecord 10, // 3: core.Certificate.issued:type_name -> google.protobuf.Timestamp 10, // 4: core.Certificate.expires:type_name -> google.protobuf.Timestamp 10, // 5: core.CertificateStatus.ocspLastUpdated:type_name -> google.protobuf.Timestamp 10, // 6: core.CertificateStatus.revokedDate:type_name -> google.protobuf.Timestamp 10, // 7: core.CertificateStatus.lastExpirationNagSent:type_name -> google.protobuf.Timestamp 10, // 8: core.CertificateStatus.notAfter:type_name -> google.protobuf.Timestamp 10, // 9: core.Registration.createdAt:type_name -> google.protobuf.Timestamp 0, // 10: core.Authorization.identifier:type_name -> core.Identifier 10, // 11: core.Authorization.expires:type_name -> google.protobuf.Timestamp 1, // 12: core.Authorization.challenges:type_name -> core.Challenge 10, // 13: core.Order.expires:type_name -> google.protobuf.Timestamp 0, // 14: core.Order.identifiers:type_name -> core.Identifier 3, // 15: core.Order.error:type_name -> core.ProblemDetails 10, // 16: core.Order.created:type_name -> google.protobuf.Timestamp 10, // 17: core.CRLEntry.revokedAt:type_name -> google.protobuf.Timestamp 18, // [18:18] is the sub-list for method output_type 18, // [18:18] is the sub-list for method input_type 18, // [18:18] is the sub-list for extension type_name 18, // [18:18] is the sub-list for extension extendee 0, // [0:18] is the sub-list for field type_name } func init() { file_core_proto_init() } func file_core_proto_init() { if File_core_proto != nil { return } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_core_proto_rawDesc), len(file_core_proto_rawDesc)), NumEnums: 0, NumMessages: 10, NumExtensions: 0, NumServices: 0, }, GoTypes: file_core_proto_goTypes, DependencyIndexes: file_core_proto_depIdxs, MessageInfos: file_core_proto_msgTypes, }.Build() File_core_proto = out.File file_core_proto_goTypes = nil file_core_proto_depIdxs = nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/letsencrypt/boulder/core/proto/core.proto ================================================ syntax = "proto3"; package core; option go_package = "github.com/letsencrypt/boulder/core/proto"; import "google/protobuf/timestamp.proto"; message Identifier { string type = 1; string value = 2; } message Challenge { // Next unused field number: 13 reserved 4, 5, 8, 11; int64 id = 1; // Fields specified by RFC 8555, Section 8. string type = 2; string url = 9; string status = 6; google.protobuf.Timestamp validated = 12; ProblemDetails error = 7; // Fields specified by individual validation methods. string token = 3; // Additional fields for our own record keeping. repeated ValidationRecord validationrecords = 10; } message ValidationRecord { // Next unused field number: 9 string hostname = 1; string port = 2; repeated bytes addressesResolved = 3; // netip.Addr.MarshalText() bytes addressUsed = 4; // netip.Addr.MarshalText() repeated string authorities = 5; string url = 6; // A list of addresses tried before the address used (see // core/objects.go and the comment on the ValidationRecord structure // definition for more information. repeated bytes addressesTried = 7; // netip.Addr.MarshalText() repeated string resolverAddrs = 8; } message ProblemDetails { string problemType = 1; string detail = 2; int32 httpStatus = 3; } message Certificate { // Next unused field number: 9 int64 registrationID = 1; string serial = 2; string digest = 3; bytes der = 4; reserved 5; // Previously issuedNS google.protobuf.Timestamp issued = 7; reserved 6; // Previously expiresNS google.protobuf.Timestamp expires = 8; } message CertificateStatus { // Next unused field number: 16 string serial = 1; reserved 2; // previously subscriberApproved string status = 3; reserved 4; // Previously ocspLastUpdatedNS google.protobuf.Timestamp ocspLastUpdated = 15; reserved 5; // Previously revokedDateNS google.protobuf.Timestamp revokedDate = 12; int64 revokedReason = 6; reserved 7; // Previously lastExpirationNagSentNS reserved 8; // previously ocspResponse google.protobuf.Timestamp lastExpirationNagSent = 13; reserved 9; // Previously notAfterNS google.protobuf.Timestamp notAfter = 14; bool isExpired = 10; int64 issuerID = 11; } message Registration { // Next unused field number: 10 int64 id = 1; bytes key = 2; reserved 3; // Previously contact reserved 4; // Previously contactsPresent string agreement = 5; reserved 6; // Previously initialIP reserved 7; // Previously createdAtNS google.protobuf.Timestamp createdAt = 9; string status = 8; } message Authorization { // Next unused field number: 12 reserved 5, 7, 8; string id = 1; int64 registrationID = 3; // Fields specified by RFC 8555, Section 7.1.4 reserved 2; // Previously dnsName Identifier identifier = 11; string status = 4; google.protobuf.Timestamp expires = 9; repeated core.Challenge challenges = 6; string certificateProfileName = 10; // We do not directly represent the "wildcard" field, instead inferring it // from the identifier value. } message Order { // Next unused field number: 17 reserved 3, 6, 10; int64 id = 1; int64 registrationID = 2; // Fields specified by RFC 8555, Section 7.1.3 // Note that we do not respect notBefore and notAfter, and we infer the // finalize and certificate URLs from the id and certificateSerial fields. string status = 7; google.protobuf.Timestamp expires = 12; reserved 8; // Previously dnsNames repeated Identifier identifiers = 16; ProblemDetails error = 4; repeated int64 v2Authorizations = 11; string certificateSerial = 5; // Additional fields for our own record-keeping. google.protobuf.Timestamp created = 13; string certificateProfileName = 14; string replaces = 15; bool beganProcessing = 9; } message CRLEntry { // Next unused field number: 5 string serial = 1; int32 reason = 2; reserved 3; // Previously revokedAtNS google.protobuf.Timestamp revokedAt = 4; } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/letsencrypt/boulder/core/util.go ================================================ package core import ( "context" "crypto" "crypto/ecdsa" "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/x509" "encoding/base64" "encoding/hex" "encoding/pem" "errors" "expvar" "fmt" "io" "math/big" mrand "math/rand/v2" "os" "path" "reflect" "regexp" "sort" "strings" "time" "unicode" "github.com/go-jose/go-jose/v4" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/timestamppb" "github.com/letsencrypt/boulder/identifier" ) const Unspecified = "Unspecified" // Package Variables Variables // BuildID is set by the compiler (using -ldflags "-X core.BuildID $(git rev-parse --short HEAD)") // and is used by GetBuildID var BuildID string // BuildHost is set by the compiler and is used by GetBuildHost var BuildHost string // BuildTime is set by the compiler and is used by GetBuildTime var BuildTime string func init() { expvar.NewString("BuildID").Set(BuildID) expvar.NewString("BuildTime").Set(BuildTime) } // Random stuff type randSource interface { Read(p []byte) (n int, err error) } // RandReader is used so that it can be replaced in tests that require // deterministic output var RandReader randSource = rand.Reader // RandomString returns a randomly generated string of the requested length. func RandomString(byteLength int) string { b := make([]byte, byteLength) _, err := io.ReadFull(RandReader, b) if err != nil { panic(fmt.Sprintf("Error reading random bytes: %s", err)) } return base64.RawURLEncoding.EncodeToString(b) } // NewToken produces a random string for Challenges, etc. func NewToken() string { return RandomString(32) } var tokenFormat = regexp.MustCompile(`^[\w-]{43}$`) // looksLikeAToken checks whether a string represents a 32-octet value in // the URL-safe base64 alphabet. func looksLikeAToken(token string) bool { return tokenFormat.MatchString(token) } // Fingerprints // Fingerprint256 produces an unpadded, URL-safe Base64-encoded SHA256 digest // of the data. func Fingerprint256(data []byte) string { d := sha256.New() _, _ = d.Write(data) // Never returns an error return base64.RawURLEncoding.EncodeToString(d.Sum(nil)) } type Sha256Digest [sha256.Size]byte // KeyDigest produces the SHA256 digest of a provided public key. func KeyDigest(key crypto.PublicKey) (Sha256Digest, error) { switch t := key.(type) { case *jose.JSONWebKey: if t == nil { return Sha256Digest{}, errors.New("cannot compute digest of nil key") } return KeyDigest(t.Key) case jose.JSONWebKey: return KeyDigest(t.Key) default: keyDER, err := x509.MarshalPKIXPublicKey(key) if err != nil { return Sha256Digest{}, err } return sha256.Sum256(keyDER), nil } } // KeyDigestB64 produces a padded, standard Base64-encoded SHA256 digest of a // provided public key. func KeyDigestB64(key crypto.PublicKey) (string, error) { digest, err := KeyDigest(key) if err != nil { return "", err } return base64.StdEncoding.EncodeToString(digest[:]), nil } // KeyDigestEquals determines whether two public keys have the same digest. func KeyDigestEquals(j, k crypto.PublicKey) bool { digestJ, errJ := KeyDigestB64(j) digestK, errK := KeyDigestB64(k) // Keys that don't have a valid digest (due to marshalling problems) // are never equal. So, e.g. nil keys are not equal. if errJ != nil || errK != nil { return false } return digestJ == digestK } // PublicKeysEqual determines whether two public keys are identical. func PublicKeysEqual(a, b crypto.PublicKey) (bool, error) { switch ak := a.(type) { case *rsa.PublicKey: return ak.Equal(b), nil case *ecdsa.PublicKey: return ak.Equal(b), nil default: return false, fmt.Errorf("unsupported public key type %T", ak) } } // SerialToString converts a certificate serial number (big.Int) to a String // consistently. func SerialToString(serial *big.Int) string { return fmt.Sprintf("%036x", serial) } // StringToSerial converts a string into a certificate serial number (big.Int) // consistently. func StringToSerial(serial string) (*big.Int, error) { var serialNum big.Int if !ValidSerial(serial) { return &serialNum, fmt.Errorf("invalid serial number %q", serial) } _, err := fmt.Sscanf(serial, "%036x", &serialNum) return &serialNum, err } // ValidSerial tests whether the input string represents a syntactically // valid serial number, i.e., that it is a valid hex string between 32 // and 36 characters long. func ValidSerial(serial string) bool { // Originally, serial numbers were 32 hex characters long. We later increased // them to 36, but we allow the shorter ones because they exist in some // production databases. if len(serial) != 32 && len(serial) != 36 { return false } _, err := hex.DecodeString(serial) return err == nil } // GetBuildID identifies what build is running. func GetBuildID() (retID string) { retID = BuildID if retID == "" { retID = Unspecified } return } // GetBuildTime identifies when this build was made func GetBuildTime() (retID string) { retID = BuildTime if retID == "" { retID = Unspecified } return } // GetBuildHost identifies the building host func GetBuildHost() (retID string) { retID = BuildHost if retID == "" { retID = Unspecified } return } // IsAnyNilOrZero returns whether any of the supplied values are nil, or (if not) // if any of them is its type's zero-value. This is useful for validating that // all required fields on a proto message are present. func IsAnyNilOrZero(vals ...any) bool { for _, val := range vals { switch v := val.(type) { case nil: return true case bool: if !v { return true } case string: if v == "" { return true } case []string: if len(v) == 0 { return true } case byte: // Byte is an alias for uint8 and will cover that case. if v == 0 { return true } case []byte: if len(v) == 0 { return true } case int: if v == 0 { return true } case int8: if v == 0 { return true } case int16: if v == 0 { return true } case int32: if v == 0 { return true } case int64: if v == 0 { return true } case uint: if v == 0 { return true } case uint16: if v == 0 { return true } case uint32: if v == 0 { return true } case uint64: if v == 0 { return true } case float32: if v == 0 { return true } case float64: if v == 0 { return true } case time.Time: if v.IsZero() { return true } case *timestamppb.Timestamp: if v == nil || v.AsTime().IsZero() { return true } case *durationpb.Duration: if v == nil || v.AsDuration() == time.Duration(0) { return true } default: if reflect.ValueOf(v).IsZero() { return true } } } return false } // UniqueLowerNames returns the set of all unique names in the input after all // of them are lowercased. The returned names will be in their lowercased form // and sorted alphabetically. func UniqueLowerNames(names []string) (unique []string) { nameMap := make(map[string]int, len(names)) for _, name := range names { nameMap[strings.ToLower(name)] = 1 } unique = make([]string, 0, len(nameMap)) for name := range nameMap { unique = append(unique, name) } sort.Strings(unique) return } // HashIdentifiers returns a hash of the identifiers requested. This is intended // for use when interacting with the orderFqdnSets table and rate limiting. func HashIdentifiers(idents identifier.ACMEIdentifiers) []byte { var values []string for _, ident := range identifier.Normalize(idents) { values = append(values, ident.Value) } hash := sha256.Sum256([]byte(strings.Join(values, ","))) return hash[:] } // LoadCert loads a PEM certificate specified by filename or returns an error func LoadCert(filename string) (*x509.Certificate, error) { certPEM, err := os.ReadFile(filename) if err != nil { return nil, err } block, _ := pem.Decode(certPEM) if block == nil { return nil, fmt.Errorf("no data in cert PEM file %q", filename) } cert, err := x509.ParseCertificate(block.Bytes) if err != nil { return nil, err } return cert, nil } // retryJitter is used to prevent bunched retried queries from falling into lockstep const retryJitter = 0.2 // RetryBackoff calculates a backoff time based on number of retries, will always // add jitter so requests that start in unison won't fall into lockstep. Because of // this the returned duration can always be larger than the maximum by a factor of // retryJitter. Adapted from // https://github.com/grpc/grpc-go/blob/v1.11.3/backoff.go#L77-L96 func RetryBackoff(retries int, base, max time.Duration, factor float64) time.Duration { if retries == 0 { return 0 } backoff, fMax := float64(base), float64(max) for backoff < fMax && retries > 1 { backoff *= factor retries-- } if backoff > fMax { backoff = fMax } // Randomize backoff delays so that if a cluster of requests start at // the same time, they won't operate in lockstep. backoff *= (1 - retryJitter) + 2*retryJitter*mrand.Float64() return time.Duration(backoff) } // IsASCII determines if every character in a string is encoded in // the ASCII character set. func IsASCII(str string) bool { for _, r := range str { if r > unicode.MaxASCII { return false } } return true } // IsCanceled returns true if err is non-nil and is either context.Canceled, or // has a grpc code of Canceled. This is useful because cancellations propagate // through gRPC boundaries, and if we choose to treat in-process cancellations a // certain way, we usually want to treat cross-process cancellations the same way. func IsCanceled(err error) bool { return errors.Is(err, context.Canceled) || status.Code(err) == codes.Canceled } func Command() string { return path.Base(os.Args[0]) } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/letsencrypt/boulder/goodkey/good_key.go ================================================ package goodkey import ( "context" "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rsa" "errors" "fmt" "math/big" "sync" "github.com/letsencrypt/boulder/core" "github.com/titanous/rocacheck" ) // To generate, run: primes 2 752 | tr '\n' , var smallPrimeInts = []int64{ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, } // singleton defines the object of a Singleton pattern var ( smallPrimesSingleton sync.Once smallPrimesProduct *big.Int ) type Config struct { // AllowedKeys enables or disables specific key algorithms and sizes. If // nil, defaults to just those keys allowed by the Let's Encrypt CPS. AllowedKeys *AllowedKeys // FermatRounds is an integer number of rounds of Fermat's factorization // method that should be performed to attempt to detect keys whose modulus can // be trivially factored because the two factors are very close to each other. // If this config value is empty or 0, it will default to 110 rounds. FermatRounds int } // AllowedKeys is a map of six specific key algorithm and size combinations to // booleans indicating whether keys of that type are considered good. type AllowedKeys struct { // Baseline Requirements, Section 6.1.5 requires key size >= 2048 and a multiple // of 8 bits: https://github.com/cabforum/servercert/blob/main/docs/BR.md#615-key-sizes // Baseline Requirements, Section 6.1.1.3 requires that we reject any keys which // have a known method to easily compute their private key, such as Debian Weak // Keys. Our enforcement mechanism relies on enumerating all Debian Weak Keys at // common key sizes, so we restrict all issuance to those common key sizes. RSA2048 bool RSA3072 bool RSA4096 bool // Baseline Requirements, Section 6.1.5 requires that ECDSA keys be valid // points on the NIST P-256, P-384, or P-521 elliptic curves. ECDSAP256 bool ECDSAP384 bool ECDSAP521 bool } // LetsEncryptCPS encodes the five key algorithms and sizes allowed by the Let's // Encrypt CPS CV-SSL Subscriber Certificate Profile: RSA 2048, RSA 3076, RSA // 4096, ECDSA 256 and ECDSA P384. // https://github.com/letsencrypt/cp-cps/blob/main/CP-CPS.md#dv-ssl-subscriber-certificate // If this is ever changed, the CP/CPS MUST be changed first. func LetsEncryptCPS() AllowedKeys { return AllowedKeys{ RSA2048: true, RSA3072: true, RSA4096: true, ECDSAP256: true, ECDSAP384: true, } } // ErrBadKey represents an error with a key. It is distinct from the various // ways in which an ACME request can have an erroneous key (BadPublicKeyError, // BadCSRError) because this library is used to check both JWS signing keys and // keys in CSRs. var ErrBadKey = errors.New("") func badKey(msg string, args ...any) error { return fmt.Errorf("%w%s", ErrBadKey, fmt.Errorf(msg, args...)) } // BlockedKeyCheckFunc is used to pass in the sa.BlockedKey functionality to KeyPolicy, // rather than storing a full sa.SQLStorageAuthority. This allows external // users who don’t want to import all of boulder/sa, and makes testing // significantly simpler. // On success, the function returns a boolean which is true if the key is blocked. type BlockedKeyCheckFunc func(ctx context.Context, keyHash []byte) (bool, error) // KeyPolicy determines which types of key may be used with various boulder // operations. type KeyPolicy struct { allowedKeys AllowedKeys fermatRounds int blockedCheck BlockedKeyCheckFunc } // NewPolicy returns a key policy based on the given configuration, with sane // defaults. If the config's AllowedKeys is nil, the LetsEncryptCPS AllowedKeys // is used. If the configured FermatRounds is 0, Fermat Factorization defaults to // attempting 110 rounds. func NewPolicy(config *Config, bkc BlockedKeyCheckFunc) (KeyPolicy, error) { if config == nil { config = &Config{} } kp := KeyPolicy{ blockedCheck: bkc, } if config.AllowedKeys == nil { kp.allowedKeys = LetsEncryptCPS() } else { kp.allowedKeys = *config.AllowedKeys } if config.FermatRounds == 0 { // The BRs require 100 rounds, so give ourselves a margin above that. kp.fermatRounds = 110 } else if config.FermatRounds < 100 { return KeyPolicy{}, fmt.Errorf("Fermat factorization rounds must be at least 100: %d", config.FermatRounds) } else { kp.fermatRounds = config.FermatRounds } return kp, nil } // GoodKey returns true if the key is acceptable for both TLS use and account // key use (our requirements are the same for either one), according to basic // strength and algorithm checking. GoodKey only supports pointers: *rsa.PublicKey // and *ecdsa.PublicKey. It will reject non-pointer types. // TODO: Support JSONWebKeys once go-jose migration is done. func (policy *KeyPolicy) GoodKey(ctx context.Context, key crypto.PublicKey) error { // Early rejection of unacceptable key types to guard subsequent checks. switch t := key.(type) { case *rsa.PublicKey, *ecdsa.PublicKey: break default: return badKey("unsupported key type %T", t) } if policy.blockedCheck != nil { digest, err := core.KeyDigest(key) if err != nil { return badKey("%w", err) } exists, err := policy.blockedCheck(ctx, digest[:]) if err != nil { return err } else if exists { return badKey("public key is forbidden") } } switch t := key.(type) { case *rsa.PublicKey: return policy.goodKeyRSA(t) case *ecdsa.PublicKey: return policy.goodKeyECDSA(t) default: return badKey("unsupported key type %T", key) } } // GoodKeyECDSA determines if an ECDSA pubkey meets our requirements func (policy *KeyPolicy) goodKeyECDSA(key *ecdsa.PublicKey) (err error) { // Check the curve. // // The validity of the curve is an assumption for all following tests. err = policy.goodCurve(key.Curve) if err != nil { return err } // Key validation routine adapted from NIST SP800-56A § 5.6.2.3.2. // // // Assuming a prime field since a) we are only allowing such curves and b) // crypto/elliptic only supports prime curves. Where this assumption // simplifies the code below, it is explicitly stated and explained. If ever // adapting this code to support non-prime curves, refer to NIST SP800-56A § // 5.6.2.3.2 and adapt this code appropriately. params := key.Params() // SP800-56A § 5.6.2.3.2 Step 1. // Partial check of the public key for an invalid range in the EC group: // Verify that key is not the point at infinity O. // This code assumes that the point at infinity is (0,0), which is the // case for all supported curves. if isPointAtInfinityNISTP(key.X, key.Y) { return badKey("key x, y must not be the point at infinity") } // SP800-56A § 5.6.2.3.2 Step 2. // "Verify that x_Q and y_Q are integers in the interval [0,p-1] in the // case that q is an odd prime p, or that x_Q and y_Q are bit strings // of length m bits in the case that q = 2**m." // // Prove prime field: ASSUMED. // Prove q != 2: ASSUMED. (Curve parameter. No supported curve has q == 2.) // Prime field && q != 2 => q is an odd prime p // Therefore "verify that x, y are in [0, p-1]" satisfies step 2. // // Therefore verify that both x and y of the public key point have the unique // correct representation of an element in the underlying field by verifying // that x and y are integers in [0, p-1]. if key.X.Sign() < 0 || key.Y.Sign() < 0 { return badKey("key x, y must not be negative") } if key.X.Cmp(params.P) >= 0 || key.Y.Cmp(params.P) >= 0 { return badKey("key x, y must not exceed P-1") } // SP800-56A § 5.6.2.3.2 Step 3. // "If q is an odd prime p, verify that (y_Q)**2 === (x_Q)***3 + a*x_Q + b (mod p). // If q = 2**m, verify that (y_Q)**2 + (x_Q)*(y_Q) == (x_Q)**3 + a*(x_Q)*2 + b in // the finite field of size 2**m. // (Ensures that the public key is on the correct elliptic curve.)" // // q is an odd prime p: proven/assumed above. // a = -3 for all supported curves. // // Therefore step 3 is satisfied simply by showing that // y**2 === x**3 - 3*x + B (mod P). // // This proves that the public key is on the correct elliptic curve. // But in practice, this test is provided by crypto/elliptic, so use that. if !key.Curve.IsOnCurve(key.X, key.Y) { return badKey("key point is not on the curve") } // SP800-56A § 5.6.2.3.2 Step 4. // "Verify that n*Q == Ø. // (Ensures that the public key has the correct order. Along with check 1, // ensures that the public key is in the correct range in the correct EC // subgroup, that is, it is in the correct EC subgroup and is not the // identity element.)" // // Ensure that public key has the correct order: // verify that n*Q = Ø. // // n*Q = Ø iff n*Q is the point at infinity (see step 1). ox, oy := key.Curve.ScalarMult(key.X, key.Y, params.N.Bytes()) if !isPointAtInfinityNISTP(ox, oy) { return badKey("public key does not have correct order") } // End of SP800-56A § 5.6.2.3.2 Public Key Validation Routine. // Key is valid. return nil } // Returns true iff the point (x,y) on NIST P-256, NIST P-384 or NIST P-521 is // the point at infinity. These curves all have the same point at infinity // (0,0). This function must ONLY be used on points on curves verified to have // (0,0) as their point at infinity. func isPointAtInfinityNISTP(x, y *big.Int) bool { return x.Sign() == 0 && y.Sign() == 0 } // GoodCurve determines if an elliptic curve meets our requirements. func (policy *KeyPolicy) goodCurve(c elliptic.Curve) (err error) { // Simply use a whitelist for now. params := c.Params() switch { case policy.allowedKeys.ECDSAP256 && params == elliptic.P256().Params(): return nil case policy.allowedKeys.ECDSAP384 && params == elliptic.P384().Params(): return nil case policy.allowedKeys.ECDSAP521 && params == elliptic.P521().Params(): return nil default: return badKey("ECDSA curve %v not allowed", params.Name) } } // GoodKeyRSA determines if a RSA pubkey meets our requirements func (policy *KeyPolicy) goodKeyRSA(key *rsa.PublicKey) error { modulus := key.N err := policy.goodRSABitLen(key) if err != nil { return err } // Rather than support arbitrary exponents, which significantly increases // the size of the key space we allow, we restrict E to the defacto standard // RSA exponent 65537. There is no specific standards document that specifies // 65537 as the 'best' exponent, but ITU X.509 Annex C suggests there are // notable merits for using it if using a fixed exponent. // // The CABF Baseline Requirements state: // The CA SHALL confirm that the value of the public exponent is an // odd number equal to 3 or more. Additionally, the public exponent // SHOULD be in the range between 2^16 + 1 and 2^256-1. // // By only allowing one exponent, which fits these constraints, we satisfy // these requirements. if key.E != 65537 { return badKey("key exponent must be 65537") } // The modulus SHOULD also have the following characteristics: an odd // number, not the power of a prime, and have no factors smaller than 752. // TODO: We don't yet check for "power of a prime." if checkSmallPrimes(modulus) { return badKey("key divisible by small prime") } // Check for weak keys generated by Infineon hardware // (see https://crocs.fi.muni.cz/public/papers/rsa_ccs17) if rocacheck.IsWeak(key) { return badKey("key generated by vulnerable Infineon-based hardware") } // Check if the key can be easily factored via Fermat's factorization method. err = checkPrimeFactorsTooClose(modulus, policy.fermatRounds) if err != nil { return badKey("key generated with factors too close together: %w", err) } return nil } func (policy *KeyPolicy) goodRSABitLen(key *rsa.PublicKey) error { // See comment on AllowedKeys above. modulusBitLen := key.N.BitLen() switch { case modulusBitLen == 2048 && policy.allowedKeys.RSA2048: return nil case modulusBitLen == 3072 && policy.allowedKeys.RSA3072: return nil case modulusBitLen == 4096 && policy.allowedKeys.RSA4096: return nil default: return badKey("key size not supported: %d", modulusBitLen) } } // Returns true iff integer i is divisible by any of the primes in smallPrimes. // // Short circuits; execution time is dependent on i. Do not use this on secret // values. // // Rather than checking each prime individually (invoking Mod on each), // multiply the primes together and let GCD do our work for us: if the // GCD between and is not one, we know we have // a bad key. This is substantially faster than checking each prime // individually. func checkSmallPrimes(i *big.Int) bool { smallPrimesSingleton.Do(func() { smallPrimesProduct = big.NewInt(1) for _, prime := range smallPrimeInts { smallPrimesProduct.Mul(smallPrimesProduct, big.NewInt(prime)) } }) // When the GCD is 1, i and smallPrimesProduct are coprime, meaning they // share no common factors. When the GCD is not one, it is the product of // all common factors, meaning we've identified at least one small prime // which invalidates i as a valid key. var result big.Int result.GCD(nil, nil, i, smallPrimesProduct) return result.Cmp(big.NewInt(1)) != 0 } // Returns an error if the modulus n is able to be factored into primes p and q // via Fermat's factorization method. This method relies on the two primes being // very close together, which means that they were almost certainly not picked // independently from a uniform random distribution. Basically, if we can factor // the key this easily, so can anyone else. func checkPrimeFactorsTooClose(n *big.Int, rounds int) error { // Pre-allocate some big numbers that we'll use a lot down below. one := big.NewInt(1) bb := new(big.Int) // Any odd integer is equal to a difference of squares of integers: // n = a^2 - b^2 = (a + b)(a - b) // Any RSA public key modulus is equal to a product of two primes: // n = pq // Here we try to find values for a and b, since doing so also gives us the // prime factors p = (a + b) and q = (a - b). // We start with a close to the square root of the modulus n, to start with // two candidate prime factors that are as close together as possible and // work our way out from there. Specifically, we set a = ceil(sqrt(n)), the // first integer greater than the square root of n. Unfortunately, big.Int's // built-in square root function takes the floor, so we have to add one to get // the ceil. a := new(big.Int) a.Sqrt(n).Add(a, one) // We calculate b2 to see if it is a perfect square (i.e. b^2), and therefore // b is an integer. Specifically, b2 = a^2 - n. b2 := new(big.Int) b2.Mul(a, a).Sub(b2, n) for round := range rounds { // To see if b2 is a perfect square, we take its square root, square that, // and check to see if we got the same result back. bb.Sqrt(b2).Mul(bb, bb) if b2.Cmp(bb) == 0 { // b2 is a perfect square, so we've found integer values of a and b, // and can easily compute p and q as their sum and difference. bb.Sqrt(bb) p := new(big.Int).Add(a, bb) q := new(big.Int).Sub(a, bb) return fmt.Errorf("public modulus n = pq factored in %d rounds into p: %s and q: %s", round+1, p, q) } // Set up the next iteration by incrementing a by one and recalculating b2. a.Add(a, one) b2.Mul(a, a).Sub(b2, n) } return nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/letsencrypt/boulder/identifier/identifier.go ================================================ // The identifier package defines types for RFC 8555 ACME identifiers. // // It exists as a separate package to prevent an import loop between the core // and probs packages. // // Function naming conventions: // - "New" creates a new instance from one or more simple base type inputs. // - "From" and "To" extract information from, or compose, a more complex object. package identifier import ( "crypto/x509" "fmt" "net" "net/netip" "slices" "strings" corepb "github.com/letsencrypt/boulder/core/proto" ) // IdentifierType is a named string type for registered ACME identifier types. // See https://tools.ietf.org/html/rfc8555#section-9.7.7 type IdentifierType string const ( // TypeDNS is specified in RFC 8555 for TypeDNS type identifiers. TypeDNS = IdentifierType("dns") // TypeIP is specified in RFC 8738 TypeIP = IdentifierType("ip") ) // IsValid tests whether the identifier type is known func (i IdentifierType) IsValid() bool { switch i { case TypeDNS, TypeIP: return true default: return false } } // ACMEIdentifier is a struct encoding an identifier that can be validated. The // protocol allows for different types of identifier to be supported (DNS // names, IP addresses, etc.), but currently we only support RFC 8555 DNS type // identifiers for domain names. type ACMEIdentifier struct { // Type is the registered IdentifierType of the identifier. Type IdentifierType `json:"type"` // Value is the value of the identifier. For a DNS type identifier it is // a domain name. Value string `json:"value"` } // ACMEIdentifiers is a named type for a slice of ACME identifiers, so that // methods can be applied to these slices. type ACMEIdentifiers []ACMEIdentifier func (i ACMEIdentifier) ToProto() *corepb.Identifier { return &corepb.Identifier{ Type: string(i.Type), Value: i.Value, } } func FromProto(ident *corepb.Identifier) ACMEIdentifier { return ACMEIdentifier{ Type: IdentifierType(ident.Type), Value: ident.Value, } } // ToProtoSlice is a convenience function for converting a slice of // ACMEIdentifier into a slice of *corepb.Identifier, to use for RPCs. func (idents ACMEIdentifiers) ToProtoSlice() []*corepb.Identifier { var pbIdents []*corepb.Identifier for _, ident := range idents { pbIdents = append(pbIdents, ident.ToProto()) } return pbIdents } // FromProtoSlice is a convenience function for converting a slice of // *corepb.Identifier from RPCs into a slice of ACMEIdentifier. func FromProtoSlice(pbIdents []*corepb.Identifier) ACMEIdentifiers { var idents ACMEIdentifiers for _, pbIdent := range pbIdents { idents = append(idents, FromProto(pbIdent)) } return idents } // NewDNS is a convenience function for creating an ACMEIdentifier with Type // "dns" for a given domain name. func NewDNS(domain string) ACMEIdentifier { return ACMEIdentifier{ Type: TypeDNS, Value: domain, } } // NewDNSSlice is a convenience function for creating a slice of ACMEIdentifier // with Type "dns" for a given slice of domain names. func NewDNSSlice(input []string) ACMEIdentifiers { var out ACMEIdentifiers for _, in := range input { out = append(out, NewDNS(in)) } return out } // NewIP is a convenience function for creating an ACMEIdentifier with Type "ip" // for a given IP address. func NewIP(ip netip.Addr) ACMEIdentifier { return ACMEIdentifier{ Type: TypeIP, // RFC 8738, Sec. 3: The identifier value MUST contain the textual form // of the address as defined in RFC 1123, Sec. 2.1 for IPv4 and in RFC // 5952, Sec. 4 for IPv6. Value: ip.WithZone("").String(), } } // FromString converts a string to an ACMEIdentifier. func FromString(identStr string) ACMEIdentifier { ip, err := netip.ParseAddr(identStr) if err == nil { return NewIP(ip) } return NewDNS(identStr) } // FromStringSlice converts a slice of strings to a slice of ACMEIdentifier. func FromStringSlice(identStrs []string) ACMEIdentifiers { var idents ACMEIdentifiers for _, identStr := range identStrs { idents = append(idents, FromString(identStr)) } return idents } // fromX509 extracts the Subject Alternative Names from a certificate or CSR's fields, and // returns a slice of ACMEIdentifiers. func fromX509(commonName string, dnsNames []string, ipAddresses []net.IP) ACMEIdentifiers { var sans ACMEIdentifiers for _, name := range dnsNames { sans = append(sans, NewDNS(name)) } if commonName != "" { // Boulder won't generate certificates with a CN that's not also present // in the SANs, but such a certificate is possible. If appended, this is // deduplicated later with Normalize(). We assume the CN is a DNSName, // because CNs are untyped strings without metadata, and we will never // configure a Boulder profile to issue a certificate that contains both // an IP address identifier and a CN. sans = append(sans, NewDNS(commonName)) } for _, ip := range ipAddresses { sans = append(sans, ACMEIdentifier{ Type: TypeIP, Value: ip.String(), }) } return Normalize(sans) } // FromCert extracts the Subject Common Name and Subject Alternative Names from // a certificate, and returns a slice of ACMEIdentifiers. func FromCert(cert *x509.Certificate) ACMEIdentifiers { return fromX509(cert.Subject.CommonName, cert.DNSNames, cert.IPAddresses) } // FromCSR extracts the Subject Common Name and Subject Alternative Names from a // CSR, and returns a slice of ACMEIdentifiers. func FromCSR(csr *x509.CertificateRequest) ACMEIdentifiers { return fromX509(csr.Subject.CommonName, csr.DNSNames, csr.IPAddresses) } // Normalize returns the set of all unique ACME identifiers in the input after // all of them are lowercased. The returned identifier values will be in their // lowercased form and sorted alphabetically by value. DNS identifiers will // precede IP address identifiers. func Normalize(idents ACMEIdentifiers) ACMEIdentifiers { for i := range idents { idents[i].Value = strings.ToLower(idents[i].Value) } slices.SortFunc(idents, func(a, b ACMEIdentifier) int { if a.Type == b.Type { if a.Value == b.Value { return 0 } if a.Value < b.Value { return -1 } return 1 } if a.Type == "dns" && b.Type == "ip" { return -1 } return 1 }) return slices.Compact(idents) } // ToValues returns a slice of DNS names and a slice of IP addresses in the // input. If an identifier type or IP address is invalid, it returns an error. func (idents ACMEIdentifiers) ToValues() ([]string, []net.IP, error) { var dnsNames []string var ipAddresses []net.IP for _, ident := range idents { switch ident.Type { case TypeDNS: dnsNames = append(dnsNames, ident.Value) case TypeIP: ip := net.ParseIP(ident.Value) if ip == nil { return nil, nil, fmt.Errorf("parsing IP address: %s", ident.Value) } ipAddresses = append(ipAddresses, ip) default: return nil, nil, fmt.Errorf("evaluating identifier type: %s for %s", ident.Type, ident.Value) } } return dnsNames, ipAddresses, nil } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/letsencrypt/boulder/probs/probs.go ================================================ package probs import ( "fmt" "net/http" "github.com/go-jose/go-jose/v4" "github.com/letsencrypt/boulder/identifier" ) const ( // Error types that can be used in ACME payloads. These are sorted in the // same order as they are defined in RFC8555 Section 6.7. We do not implement // the `compound`, `externalAccountRequired`, or `userActionRequired` errors, // because we have no path that would return them. AccountDoesNotExistProblem = ProblemType("accountDoesNotExist") // AlreadyReplacedProblem is a problem type that is defined in Section 7.4 // of draft-ietf-acme-ari-08, for more information see: // https://datatracker.ietf.org/doc/html/draft-ietf-acme-ari-08#section-7.4 AlreadyReplacedProblem = ProblemType("alreadyReplaced") AlreadyRevokedProblem = ProblemType("alreadyRevoked") BadCSRProblem = ProblemType("badCSR") BadNonceProblem = ProblemType("badNonce") BadPublicKeyProblem = ProblemType("badPublicKey") BadRevocationReasonProblem = ProblemType("badRevocationReason") BadSignatureAlgorithmProblem = ProblemType("badSignatureAlgorithm") CAAProblem = ProblemType("caa") // ConflictProblem is a problem type that is not defined in RFC8555. ConflictProblem = ProblemType("conflict") ConnectionProblem = ProblemType("connection") DNSProblem = ProblemType("dns") InvalidContactProblem = ProblemType("invalidContact") MalformedProblem = ProblemType("malformed") OrderNotReadyProblem = ProblemType("orderNotReady") PausedProblem = ProblemType("rateLimited") RateLimitedProblem = ProblemType("rateLimited") RejectedIdentifierProblem = ProblemType("rejectedIdentifier") ServerInternalProblem = ProblemType("serverInternal") TLSProblem = ProblemType("tls") UnauthorizedProblem = ProblemType("unauthorized") UnsupportedContactProblem = ProblemType("unsupportedContact") UnsupportedIdentifierProblem = ProblemType("unsupportedIdentifier") // Defined in https://datatracker.ietf.org/doc/draft-aaron-acme-profiles/ InvalidProfileProblem = ProblemType("invalidProfile") ErrorNS = "urn:ietf:params:acme:error:" ) // ProblemType defines the error types in the ACME protocol type ProblemType string // ProblemDetails objects represent problem documents // https://tools.ietf.org/html/draft-ietf-appsawg-http-problem-00 type ProblemDetails struct { Type ProblemType `json:"type,omitempty"` Detail string `json:"detail,omitempty"` // HTTPStatus is the HTTP status code the ProblemDetails should probably be sent // as. HTTPStatus int `json:"status,omitempty"` // SubProblems are optional additional per-identifier problems. See // RFC 8555 Section 6.7.1: https://tools.ietf.org/html/rfc8555#section-6.7.1 SubProblems []SubProblemDetails `json:"subproblems,omitempty"` // Algorithms is an extension field defined only for problem documents of type // badSignatureAlgorithm. See RFC 8555, Section 6.2: // https://datatracker.ietf.org/doc/html/rfc8555#section-6.2 Algorithms []jose.SignatureAlgorithm `json:"algorithms,omitempty"` } // SubProblemDetails represents sub-problems specific to an identifier that are // related to a top-level ProblemDetails. // See RFC 8555 Section 6.7.1: https://tools.ietf.org/html/rfc8555#section-6.7.1 type SubProblemDetails struct { ProblemDetails Identifier identifier.ACMEIdentifier `json:"identifier"` } func (pd *ProblemDetails) String() string { return fmt.Sprintf("%s :: %s", pd.Type, pd.Detail) } // WithSubProblems returns a new ProblemsDetails instance created by adding the // provided subProbs to the existing ProblemsDetail. func (pd *ProblemDetails) WithSubProblems(subProbs []SubProblemDetails) *ProblemDetails { return &ProblemDetails{ Type: pd.Type, Detail: pd.Detail, HTTPStatus: pd.HTTPStatus, SubProblems: append(pd.SubProblems, subProbs...), } } // Helper functions which construct the basic RFC8555 Problem Documents, with // the Type already set and the Details supplied by the caller. // AccountDoesNotExist returns a ProblemDetails representing an // AccountDoesNotExistProblem error func AccountDoesNotExist(detail string) *ProblemDetails { return &ProblemDetails{ Type: AccountDoesNotExistProblem, Detail: detail, HTTPStatus: http.StatusBadRequest, } } // AlreadyReplaced returns a ProblemDetails with a AlreadyReplacedProblem and a // 409 Conflict status code. func AlreadyReplaced(detail string) *ProblemDetails { return &ProblemDetails{ Type: AlreadyReplacedProblem, Detail: detail, HTTPStatus: http.StatusConflict, } } // AlreadyRevoked returns a ProblemDetails with a AlreadyRevokedProblem and a 400 Bad // Request status code. func AlreadyRevoked(detail string) *ProblemDetails { return &ProblemDetails{ Type: AlreadyRevokedProblem, Detail: detail, HTTPStatus: http.StatusBadRequest, } } // BadCSR returns a ProblemDetails representing a BadCSRProblem. func BadCSR(detail string) *ProblemDetails { return &ProblemDetails{ Type: BadCSRProblem, Detail: detail, HTTPStatus: http.StatusBadRequest, } } // BadNonce returns a ProblemDetails with a BadNonceProblem and a 400 Bad // Request status code. func BadNonce(detail string) *ProblemDetails { return &ProblemDetails{ Type: BadNonceProblem, Detail: detail, HTTPStatus: http.StatusBadRequest, } } // BadPublicKey returns a ProblemDetails with a BadPublicKeyProblem and a 400 Bad // Request status code. func BadPublicKey(detail string) *ProblemDetails { return &ProblemDetails{ Type: BadPublicKeyProblem, Detail: detail, HTTPStatus: http.StatusBadRequest, } } // BadRevocationReason returns a ProblemDetails representing // a BadRevocationReasonProblem func BadRevocationReason(detail string) *ProblemDetails { return &ProblemDetails{ Type: BadRevocationReasonProblem, Detail: detail, HTTPStatus: http.StatusBadRequest, } } // BadSignatureAlgorithm returns a ProblemDetails with a BadSignatureAlgorithmProblem // and a 400 Bad Request status code. func BadSignatureAlgorithm(detail string) *ProblemDetails { return &ProblemDetails{ Type: BadSignatureAlgorithmProblem, Detail: detail, HTTPStatus: http.StatusBadRequest, } } // CAA returns a ProblemDetails representing a CAAProblem func CAA(detail string) *ProblemDetails { return &ProblemDetails{ Type: CAAProblem, Detail: detail, HTTPStatus: http.StatusForbidden, } } // Connection returns a ProblemDetails representing a ConnectionProblem // error func Connection(detail string) *ProblemDetails { return &ProblemDetails{ Type: ConnectionProblem, Detail: detail, HTTPStatus: http.StatusBadRequest, } } // DNS returns a ProblemDetails representing a DNSProblem func DNS(detail string) *ProblemDetails { return &ProblemDetails{ Type: DNSProblem, Detail: detail, HTTPStatus: http.StatusBadRequest, } } // InvalidContact returns a ProblemDetails representing an InvalidContactProblem. func InvalidContact(detail string) *ProblemDetails { return &ProblemDetails{ Type: InvalidContactProblem, Detail: detail, HTTPStatus: http.StatusBadRequest, } } // Malformed returns a ProblemDetails with a MalformedProblem and a 400 Bad // Request status code. func Malformed(detail string, a ...any) *ProblemDetails { if len(a) > 0 { detail = fmt.Sprintf(detail, a...) } return &ProblemDetails{ Type: MalformedProblem, Detail: detail, HTTPStatus: http.StatusBadRequest, } } // OrderNotReady returns a ProblemDetails representing a OrderNotReadyProblem func OrderNotReady(detail string) *ProblemDetails { return &ProblemDetails{ Type: OrderNotReadyProblem, Detail: detail, HTTPStatus: http.StatusForbidden, } } // RateLimited returns a ProblemDetails representing a RateLimitedProblem error func RateLimited(detail string) *ProblemDetails { return &ProblemDetails{ Type: RateLimitedProblem, Detail: detail, HTTPStatus: http.StatusTooManyRequests, } } // Paused returns a ProblemDetails representing a RateLimitedProblem error func Paused(detail string) *ProblemDetails { return &ProblemDetails{ Type: PausedProblem, Detail: detail, HTTPStatus: http.StatusTooManyRequests, } } // RejectedIdentifier returns a ProblemDetails with a RejectedIdentifierProblem and a 400 Bad // Request status code. func RejectedIdentifier(detail string) *ProblemDetails { return &ProblemDetails{ Type: RejectedIdentifierProblem, Detail: detail, HTTPStatus: http.StatusBadRequest, } } // ServerInternal returns a ProblemDetails with a ServerInternalProblem and a // 500 Internal Server Failure status code. func ServerInternal(detail string) *ProblemDetails { return &ProblemDetails{ Type: ServerInternalProblem, Detail: detail, HTTPStatus: http.StatusInternalServerError, } } // TLS returns a ProblemDetails representing a TLSProblem error func TLS(detail string) *ProblemDetails { return &ProblemDetails{ Type: TLSProblem, Detail: detail, HTTPStatus: http.StatusBadRequest, } } // Unauthorized returns a ProblemDetails with an UnauthorizedProblem and a 403 // Forbidden status code. func Unauthorized(detail string) *ProblemDetails { return &ProblemDetails{ Type: UnauthorizedProblem, Detail: detail, HTTPStatus: http.StatusForbidden, } } // UnsupportedContact returns a ProblemDetails representing an // UnsupportedContactProblem func UnsupportedContact(detail string) *ProblemDetails { return &ProblemDetails{ Type: UnsupportedContactProblem, Detail: detail, HTTPStatus: http.StatusBadRequest, } } // UnsupportedIdentifier returns a ProblemDetails representing an // UnsupportedIdentifierProblem func UnsupportedIdentifier(detail string, a ...any) *ProblemDetails { return &ProblemDetails{ Type: UnsupportedIdentifierProblem, Detail: fmt.Sprintf(detail, a...), HTTPStatus: http.StatusBadRequest, } } // Additional helper functions that return variations on MalformedProblem with // different HTTP status codes set. // Canceled returns a ProblemDetails with a MalformedProblem and a 408 Request // Timeout status code. func Canceled(detail string, a ...any) *ProblemDetails { if len(a) > 0 { detail = fmt.Sprintf(detail, a...) } return &ProblemDetails{ Type: MalformedProblem, Detail: detail, HTTPStatus: http.StatusRequestTimeout, } } // Conflict returns a ProblemDetails with a ConflictProblem and a 409 Conflict // status code. func Conflict(detail string) *ProblemDetails { return &ProblemDetails{ Type: ConflictProblem, Detail: detail, HTTPStatus: http.StatusConflict, } } // MethodNotAllowed returns a ProblemDetails representing a disallowed HTTP // method error. func MethodNotAllowed() *ProblemDetails { return &ProblemDetails{ Type: MalformedProblem, Detail: "Method not allowed", HTTPStatus: http.StatusMethodNotAllowed, } } // NotFound returns a ProblemDetails with a MalformedProblem and a 404 Not Found // status code. func NotFound(detail string) *ProblemDetails { return &ProblemDetails{ Type: MalformedProblem, Detail: detail, HTTPStatus: http.StatusNotFound, } } // InvalidProfile returns a ProblemDetails with type InvalidProfile, specified // in https://datatracker.ietf.org/doc/draft-aaron-acme-profiles/. func InvalidProfile(detail string) *ProblemDetails { return &ProblemDetails{ Type: InvalidProfileProblem, Detail: detail, HTTPStatus: http.StatusBadRequest, } } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/letsencrypt/boulder/revocation/reasons.go ================================================ package revocation import ( "fmt" ) // Reason is used to specify a certificate revocation reason type Reason int64 // The enumerated reasons for revoking a certificate. See RFC 5280: // https://datatracker.ietf.org/doc/html/rfc5280#section-5.3.1. const ( Unspecified Reason = 0 KeyCompromise Reason = 1 CACompromise Reason = 2 AffiliationChanged Reason = 3 Superseded Reason = 4 CessationOfOperation Reason = 5 CertificateHold Reason = 6 // 7 is unused RemoveFromCRL Reason = 8 PrivilegeWithdrawn Reason = 9 AACompromise Reason = 10 ) // reasonToString provides a map from reason code to string. It is unexported // to make it immutable. var reasonToString = map[Reason]string{ Unspecified: "unspecified", KeyCompromise: "keyCompromise", CACompromise: "cACompromise", AffiliationChanged: "affiliationChanged", Superseded: "superseded", CessationOfOperation: "cessationOfOperation", CertificateHold: "certificateHold", RemoveFromCRL: "removeFromCRL", PrivilegeWithdrawn: "privilegeWithdrawn", AACompromise: "aAcompromise", } // String converts a revocation reason code (such as 0) into its corresponding // reason string (e.g. "unspecified"). // // The receiver *must* be one of the valid reason code constants defined in this // package: this method will panic if called on an invalid Reason. It is // expected that this method is only called on const Reasons, or after a call to // UserAllowedReason or AdminAllowedReason. func (r Reason) String() string { res, ok := reasonToString[r] if !ok { panic(fmt.Errorf("unrecognized revocation code %d", r)) } return res } // StringToReason converts a revocation reason string (such as "keyCompromise") // into the corresponding integer reason code (e.g. 1). func StringToReason(s string) (Reason, error) { for code, str := range reasonToString { if s == str { return code, nil } } return 0, fmt.Errorf("unrecognized revocation reason %q", s) } // UserAllowedReason returns true if the given Reason is in the subset of // Reasons which users are allowed to request. func UserAllowedReason(r Reason) bool { switch r { case Unspecified, KeyCompromise, Superseded, CessationOfOperation: return true } return false } // AdminAllowedReason returns true if the given Reason is in the subset of // Reasons which admins (i.e. people acting in CA Trusted Roles) are allowed // to request. Reasons which do *not* appear here are those which are defined // by RFC 5280 but are disallowed by the Baseline Requirements. func AdminAllowedReason(r Reason) bool { switch r { case Unspecified, KeyCompromise, Superseded, CessationOfOperation, PrivilegeWithdrawn: return true } return false } ================================================ FILE: third_party/VENDOR-LICENSE/github.com/mitchellh/go-homedir/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2013 Mitchell Hashimoto Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/mitchellh/go-wordwrap/LICENSE.md ================================================ The MIT License (MIT) Copyright (c) 2014 Mitchell Hashimoto Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/mitchellh/mapstructure/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2013 Mitchell Hashimoto Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/moby/docker-image-spec/specs-go/v1/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/moby/term/LICENSE ================================================ Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS Copyright 2013-2018 Docker, Inc. 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 https://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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/modern-go/concurrent/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/modern-go/reflect2/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/mozillazg/docker-credential-acr-helper/pkg/LICENSE ================================================ MIT License Copyright (c) 2022 mozillazg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/munnerz/goautoneg/LICENSE ================================================ Copyright (c) 2011, Open Knowledge Foundation Ltd. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the Open Knowledge Foundation Ltd. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/natefinch/atomic/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2015 Nate Finch Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/nozzle/throttler/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/oklog/ulid/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/open-policy-agent/opa/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/open-policy-agent/opa/internal/edittree/bitvector/license.txt ================================================ Copyright (c) 2014 Dropbox, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/open-policy-agent/opa/internal/gojsonschema/LICENSE-APACHE-2.0.txt ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2015 xeipuuv 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/open-policy-agent/opa/internal/semver/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/opencontainers/go-digest/LICENSE ================================================ Apache License Version 2.0, January 2004 https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS Copyright 2019, 2020 OCI Contributors Copyright 2016 Docker, Inc. 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 https://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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/opencontainers/image-spec/specs-go/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS Copyright 2016 The Linux Foundation. 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/pelletier/go-toml/v2/LICENSE ================================================ The MIT License (MIT) go-toml v2 Copyright (c) 2021 - 2023 Thomas Pelletier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/pkg/browser/LICENSE ================================================ Copyright (c) 2014, Dave Cheney All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/pkg/errors/LICENSE ================================================ Copyright (c) 2015, Dave Cheney All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/pmezard/go-difflib/difflib/LICENSE ================================================ Copyright (c) 2013, Patrick Mezard All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil/LICENSE ================================================ Copyright (c) 2013 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/prometheus/client_golang/prometheus/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/prometheus/client_golang/prometheus/NOTICE ================================================ Prometheus instrumentation library for Go applications Copyright 2012-2015 The Prometheus Authors This product includes software developed at SoundCloud Ltd. (http://soundcloud.com/). The following components are included in this product: perks - a fork of https://github.com/bmizerany/perks https://github.com/beorn7/perks Copyright 2013-2015 Blake Mizerany, Björn Rabenstein See https://github.com/beorn7/perks/blob/master/README.md for license details. Go support for Protocol Buffers - Google's data interchange format http://github.com/golang/protobuf/ Copyright 2010 The Go Authors See source code for license details. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/prometheus/client_model/go/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/prometheus/client_model/go/NOTICE ================================================ Data model artifacts for Prometheus. Copyright 2012-2015 The Prometheus Authors This product includes software developed at SoundCloud Ltd. (http://soundcloud.com/). ================================================ FILE: third_party/VENDOR-LICENSE/github.com/prometheus/common/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/prometheus/common/NOTICE ================================================ Common libraries shared by Prometheus Go components. Copyright 2015 The Prometheus Authors This product includes software developed at SoundCloud Ltd. (http://soundcloud.com/). ================================================ FILE: third_party/VENDOR-LICENSE/github.com/prometheus/procfs/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/prometheus/procfs/NOTICE ================================================ procfs provides functions to retrieve system, kernel and process metrics from the pseudo-filesystem proc. Copyright 2014-2015 The Prometheus Authors This product includes software developed at SoundCloud Ltd. (http://soundcloud.com/). ================================================ FILE: third_party/VENDOR-LICENSE/github.com/prometheus/statsd_exporter/pkg/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/prometheus/statsd_exporter/pkg/NOTICE ================================================ StatsD-to-Prometheus exporter Copyright 2013-2015 The Prometheus Authors This product includes software developed at SoundCloud Ltd. (http://soundcloud.com/). ================================================ FILE: third_party/VENDOR-LICENSE/github.com/protocolbuffers/txtpbfmt/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/rcrowley/go-metrics/LICENSE ================================================ Copyright 2012 Richard Crowley. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY RICHARD CROWLEY ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RICHARD CROWLEY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of Richard Crowley. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/ryanuber/go-glob/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 Ryan Uber Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/sagikazarmark/locafero/LICENSE ================================================ Copyright (c) 2023 Márk Sági-Kazár Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/sassoftware/relic/lib/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/secure-systems-lab/go-securesystemslib/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2021 NYU Secure Systems Lab Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/shibumi/go-pathspec/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/sigstore/cosign/v3/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/sigstore/protobuf-specs/gen/pb-go/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/sigstore/rekor/pkg/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/sigstore/rekor-tiles/v2/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/sigstore/scaffolding/pkg/repo/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/sigstore/sigstore/pkg/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/sigstore/sigstore/pkg/signature/kms/aws/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/sigstore/sigstore/pkg/signature/kms/azure/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/sigstore/sigstore/pkg/signature/kms/gcp/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/sigstore/sigstore/pkg/signature/kms/hashivault/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/sigstore/sigstore-go/pkg/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/sigstore/timestamp-authority/v2/pkg/verification/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/sirupsen/logrus/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 Simon Eskildsen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/sourcegraph/conc/LICENSE ================================================ MIT License Copyright (c) 2023 Sourcegraph Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/spf13/afero/LICENSE.txt ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/spf13/cast/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 Steve Francia Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/spf13/cobra/LICENSE.txt ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/spf13/pflag/LICENSE ================================================ Copyright (c) 2012 Alex Ogier. All rights reserved. Copyright (c) 2012 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/spf13/viper/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 Steve Francia Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/subosito/gotenv/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2013 Alif Rachmawadi Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/syndtr/goleveldb/leveldb/LICENSE ================================================ Copyright 2012 Suryandaru Triandana All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/tchap/go-patricia/v2/patricia/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 The AUTHORS Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/theupdateframework/go-tuf/LICENSE ================================================ Copyright (c) 2014-2020 Prime Directive, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Prime Directive, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/theupdateframework/go-tuf/v2/metadata/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2024 The Update Framework 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/theupdateframework/go-tuf/v2/metadata/NOTICE ================================================ Copyright 2024 The Update Framework Authors Apache 2.0 License Copyright 2024 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (/). SPDX-License-Identifier: Apache-2.0 ================================================ FILE: third_party/VENDOR-LICENSE/github.com/titanous/rocacheck/LICENSE ================================================ MIT License Copyright (c) 2017, Jonathan Rudenberg Copyright (c) 2017, CRoCS, EnigmaBridge Ltd. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/tjfoc/gmsm/sm3/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/transparency-dev/formats/log/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/transparency-dev/merkle/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/valyala/fastjson/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2018 Aliaksandr Valialkin Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/vbatts/tar-split/archive/tar/LICENSE ================================================ Copyright (c) 2015 Vincent Batts, Raleigh, NC, USA All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/vektah/gqlparser/v2/LICENSE ================================================ Copyright (c) 2018 Adam Scarr Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/x448/float16/LICENSE ================================================ MIT License Copyright (c) 2019 Montgomery Edwards⁴⁴⁸ and Faye Amacker Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/xeipuuv/gojsonpointer/LICENSE-APACHE-2.0.txt ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2015 xeipuuv 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/xeipuuv/gojsonreference/LICENSE-APACHE-2.0.txt ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2015 xeipuuv 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. ================================================ FILE: third_party/VENDOR-LICENSE/github.com/yashtewari/glob-intersection/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} 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. ================================================ FILE: third_party/VENDOR-LICENSE/gitlab.com/gitlab-org/api/client-go/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} 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. ================================================ FILE: third_party/VENDOR-LICENSE/go.mongodb.org/mongo-driver/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/go.opencensus.io/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/go.opentelemetry.io/auto/sdk/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. -------------------------------------------------------------------------------- Copyright 2009 The Go Authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. -------------------------------------------------------------------------------- Copyright 2009 The Go Authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/go.opentelemetry.io/otel/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. -------------------------------------------------------------------------------- Copyright 2009 The Go Authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/go.opentelemetry.io/otel/metric/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. -------------------------------------------------------------------------------- Copyright 2009 The Go Authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/go.opentelemetry.io/otel/sdk/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. -------------------------------------------------------------------------------- Copyright 2009 The Go Authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/go.opentelemetry.io/otel/trace/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. -------------------------------------------------------------------------------- Copyright 2009 The Go Authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/go.uber.org/atomic/LICENSE.txt ================================================ Copyright (c) 2016 Uber Technologies, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/go.uber.org/automaxprocs/LICENSE ================================================ Copyright (c) 2017 Uber Technologies, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/go.uber.org/multierr/LICENSE.txt ================================================ Copyright (c) 2017-2021 Uber Technologies, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/go.uber.org/zap/LICENSE ================================================ Copyright (c) 2016-2024 Uber Technologies, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: third_party/VENDOR-LICENSE/go.yaml.in/yaml/v2/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} 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. ================================================ FILE: third_party/VENDOR-LICENSE/go.yaml.in/yaml/v2/NOTICE ================================================ Copyright 2011-2016 Canonical Ltd. 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. ================================================ FILE: third_party/VENDOR-LICENSE/go.yaml.in/yaml/v3/LICENSE ================================================ This project is covered by two different licenses: MIT and Apache. #### MIT License #### The following files were ported to Go from C files of libyaml, and thus are still covered by their original MIT license, with the additional copyright staring in 2011 when the project was ported over: apic.go emitterc.go parserc.go readerc.go scannerc.go writerc.go yamlh.go yamlprivateh.go Copyright (c) 2006-2010 Kirill Simonov Copyright (c) 2006-2011 Kirill Simonov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ### Apache License ### All the remaining project files are covered by the Apache license: Copyright (c) 2011-2019 Canonical Ltd 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. ================================================ FILE: third_party/VENDOR-LICENSE/go.yaml.in/yaml/v3/NOTICE ================================================ Copyright 2011-2016 Canonical Ltd. 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. ================================================ FILE: third_party/VENDOR-LICENSE/golang.org/x/crypto/LICENSE ================================================ Copyright 2009 The Go Authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/golang.org/x/mod/LICENSE ================================================ Copyright 2009 The Go Authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/golang.org/x/net/LICENSE ================================================ Copyright 2009 The Go Authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/golang.org/x/oauth2/LICENSE ================================================ Copyright 2009 The Go Authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/golang.org/x/sync/LICENSE ================================================ Copyright 2009 The Go Authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/golang.org/x/sys/LICENSE ================================================ Copyright 2009 The Go Authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/golang.org/x/term/LICENSE ================================================ Copyright 2009 The Go Authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/golang.org/x/text/LICENSE ================================================ Copyright 2009 The Go Authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/golang.org/x/time/rate/LICENSE ================================================ Copyright 2009 The Go Authors. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google LLC nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/gomodules.xyz/jsonpatch/v2/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} 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. ================================================ FILE: third_party/VENDOR-LICENSE/google.golang.org/api/LICENSE ================================================ Copyright (c) 2011 Google Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/google.golang.org/api/internal/third_party/uritemplates/LICENSE ================================================ Copyright (c) 2013 Joshua Tacoma. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/google.golang.org/genproto/googleapis/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/google.golang.org/genproto/googleapis/api/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/google.golang.org/genproto/googleapis/rpc/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/google.golang.org/grpc/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/google.golang.org/grpc/NOTICE.txt ================================================ Copyright 2014 gRPC 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. ================================================ FILE: third_party/VENDOR-LICENSE/google.golang.org/protobuf/LICENSE ================================================ Copyright (c) 2018 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/gopkg.in/evanphx/json-patch.v4/LICENSE ================================================ Copyright (c) 2014, Evan Phoenix All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Evan Phoenix nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/gopkg.in/inf.v0/LICENSE ================================================ Copyright (c) 2012 Péter Surányi. Portions Copyright (c) 2009 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/gopkg.in/ini.v1/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2014 Unknwon 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. ================================================ FILE: third_party/VENDOR-LICENSE/gopkg.in/yaml.v2/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} 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. ================================================ FILE: third_party/VENDOR-LICENSE/gopkg.in/yaml.v2/NOTICE ================================================ Copyright 2011-2016 Canonical Ltd. 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. ================================================ FILE: third_party/VENDOR-LICENSE/gopkg.in/yaml.v3/LICENSE ================================================ This project is covered by two different licenses: MIT and Apache. #### MIT License #### The following files were ported to Go from C files of libyaml, and thus are still covered by their original MIT license, with the additional copyright staring in 2011 when the project was ported over: apic.go emitterc.go parserc.go readerc.go scannerc.go writerc.go yamlh.go yamlprivateh.go Copyright (c) 2006-2010 Kirill Simonov Copyright (c) 2006-2011 Kirill Simonov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ### Apache License ### All the remaining project files are covered by the Apache license: Copyright (c) 2011-2019 Canonical Ltd 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. ================================================ FILE: third_party/VENDOR-LICENSE/gopkg.in/yaml.v3/NOTICE ================================================ Copyright 2011-2016 Canonical Ltd. 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. ================================================ FILE: third_party/VENDOR-LICENSE/k8s.io/api/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/k8s.io/apiextensions-apiserver/pkg/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/k8s.io/apimachinery/pkg/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/k8s.io/apimachinery/third_party/forked/golang/LICENSE ================================================ Copyright (c) 2009 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/k8s.io/client-go/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/k8s.io/klog/v2/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/k8s.io/kube-openapi/pkg/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json/LICENSE ================================================ Copyright (c) 2020 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/k8s.io/kube-openapi/pkg/validation/spec/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/k8s.io/utils/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/k8s.io/utils/internal/third_party/forked/golang/LICENSE ================================================ Copyright (c) 2012 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/knative.dev/hack/schema/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/knative.dev/pkg/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: third_party/VENDOR-LICENSE/sigs.k8s.io/json/LICENSE ================================================ Files other than internal/golang/* licensed under: Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} 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. ------------------ internal/golang/* files licensed under: Copyright (c) 2009 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: third_party/VENDOR-LICENSE/sigs.k8s.io/randfill/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2014 The gofuzz Authors Copyright 2025 The Kubernetes 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. ================================================ FILE: third_party/VENDOR-LICENSE/sigs.k8s.io/randfill/NOTICE ================================================ When donating the randfill project to the CNCF, we could not reach all the gofuzz contributors to sign the CNCF CLA. As such, according to the CNCF rules to donate a repository, we must add a NOTICE referencing section 7 of the CLA with a list of developers who could not be reached. `7. Should You wish to submit work that is not Your original creation, You may submit it to the Foundation separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here]".` Submitted on behalf of a third-party: @dnephin (Daniel Nephin) Submitted on behalf of a third-party: @AlekSi (Alexey Palazhchenko) Submitted on behalf of a third-party: @bbigras (Bruno Bigras) Submitted on behalf of a third-party: @samirkut (Samir) Submitted on behalf of a third-party: @posener (Eyal Posener) Submitted on behalf of a third-party: @Ashikpaul (Ashik Paul) Submitted on behalf of a third-party: @kwongtailau (Kwongtai) Submitted on behalf of a third-party: @ericcornelissen (Eric Cornelissen) Submitted on behalf of a third-party: @eclipseo (Robert-André Mauchin) Submitted on behalf of a third-party: @yanzhoupan (Andrew Pan) Submitted on behalf of a third-party: @STRRL (Zhiqiang ZHOU) Submitted on behalf of a third-party: @disconnect3d (Disconnect3d) ================================================ FILE: third_party/VENDOR-LICENSE/sigs.k8s.io/release-utils/version/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} 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. ================================================ FILE: third_party/VENDOR-LICENSE/sigs.k8s.io/structured-merge-diff/v6/LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} 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. ================================================ FILE: third_party/VENDOR-LICENSE/sigs.k8s.io/yaml/LICENSE ================================================ The MIT License (MIT) Copyright (c) 2014 Sam Ghods Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Copyright (c) 2012 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # The forked go-yaml.v3 library under this project is covered by two different licenses (MIT and Apache): #### MIT License #### The following files were ported to Go from C files of libyaml, and thus are still covered by their original MIT license, with the additional copyright staring in 2011 when the project was ported over: apic.go emitterc.go parserc.go readerc.go scannerc.go writerc.go yamlh.go yamlprivateh.go Copyright (c) 2006-2010 Kirill Simonov Copyright (c) 2006-2011 Kirill Simonov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ### Apache License ### All the remaining project files are covered by the Apache license: Copyright (c) 2011-2019 Canonical Ltd 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. # The forked go-yaml.v2 library under the project is covered by an Apache license: Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} 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.