From 4c1346c6e2111520eb77c6b68caa675d5ff4095d Mon Sep 17 00:00:00 2001 From: Abrar Shivani Date: Thu, 27 Aug 2026 10:11:48 -0700 Subject: [PATCH 1/4] Add version and verified upstream license links to the notices THIRD_PARTY_NOTICES.md now carries a Version and a Location column instead of the Dependency column. Location links to the license file in the dependency's own upstream repository, pinned to the version we redistribute: | Package | Version | License | Location | |---------|---------|---------|----------| | `github.com/NVIDIA/go-nvml/pkg` | v0.13.3-1 | Apache-2.0 | [LICENSE](https://github.com/NVIDIA/go-nvml/blob/v0.13.3-1/LICENSE) | Version was dropped in 93ebcb6ad because the notices were meant to identify dependencies rather than a build. That is reversed here: a notices file that does not say which version it describes cannot be matched to a release, and a link into upstream needs a ref to point at. The churn per bump is one index row and two bullets. Every URL was verified by fetching it and comparing its sha256 against the copy under vendor/. A URL that does not match is never written, so no link is dead and none points at the wrong license. 96 URLs across 72 modules. vendor/ gives the module, the version and the license file names for free, but not the upstream repository: cyphar.com/go-pathrs lives at github.com/cyphar/go-pathrs, k8s.io/api at github.com/kubernetes/api. Two committed maps carry that instead, both machine-generated. hack/module-repos.tsv maps module to repository, resolved from the Go module proxy's Origin, then the go-import meta tag that go get itself uses, then the github.com// path shape. It is keyed by module and not by version, so a bump does not invalidate it. hack/license-urls.tsv maps module, version and license path to a verified URL. A row is written only when the bytes at that URL hash identically to the vendored copy. Probing for a 200 is not enough: it cannot tell a correct link from one that returns 200 for the wrong license. Both are produced out of band by 'make third-party-notices-repos' and 'make third-party-notices-urls', which need network. 'make third-party-notices' reads them offline, so 'make check-third-party-notices' stays hermetic. License files are now enumerated from vendor/ rather than from the go-licenses save output, because that output keeps only the one file it classifies as the license per package and drops the rest. That recovers nine PATENTS files, the LICENSE.libyaml that go.yaml.in/yaml/v2 ships alongside its Apache-2.0 LICENSE, and several AUTHORS and NOTICE files. hack/license-overrides.tsv corrects the License column where go-licenses under-reports it. Three modules ship one file holding two licenses, so they read Apache-2.0 / MIT from the override. It is curated by hand rather than detected, because scanning license text cannot tell BSD-2-Clause from BSD-3-Clause and a wrong addition is worse than an omission. Generation fails if an override names a package no longer in the index, so it cannot rot unnoticed. third-party-notices-links.yaml re-verifies every URL weekly. Links are proven correct when written, but upstream can retag or archive a repository afterwards and no offline gate can see that. A version change now needs two commands, because a verified URL contains the version: make third-party-notices-urls # network make third-party-notices # offline Dependabot cannot do the first on its own; its bump job needs wiring, or a human runs it. That is the direct cost of requiring every link to be verified rather than derived. 'make test-tools' runs the new bash suites, 54 assertions across two files, and is part of CHECK_TARGETS so it runs in CI. Signed-off-by: Abrar Shivani --- .../workflows/third-party-notices-check.yaml | 6 + .../workflows/third-party-notices-links.yaml | 62 ++ Makefile | 19 +- THIRD_PARTY_NOTICES.md | 810 ++++++++++++++---- hack/generate-third-party-notices.sh | 227 +++-- hack/generate-third-party-notices_test.sh | 194 +++++ hack/license-overrides.tsv | 16 + hack/license-url-lib.sh | 156 ++++ hack/license-url-lib_test.sh | 91 ++ hack/license-urls.tsv | 101 +++ hack/module-repos.tsv | 76 ++ hack/resolve-module-repos.sh | 173 ++++ hack/test-helpers.sh | 45 + hack/verify-license-urls.sh | 226 +++++ 14 files changed, 1998 insertions(+), 204 deletions(-) create mode 100644 .github/workflows/third-party-notices-links.yaml create mode 100755 hack/generate-third-party-notices_test.sh create mode 100644 hack/license-overrides.tsv create mode 100755 hack/license-url-lib.sh create mode 100755 hack/license-url-lib_test.sh create mode 100644 hack/license-urls.tsv create mode 100644 hack/module-repos.tsv create mode 100755 hack/resolve-module-repos.sh create mode 100755 hack/test-helpers.sh create mode 100755 hack/verify-license-urls.sh diff --git a/.github/workflows/third-party-notices-check.yaml b/.github/workflows/third-party-notices-check.yaml index 94a6a185d..bd7202257 100644 --- a/.github/workflows/third-party-notices-check.yaml +++ b/.github/workflows/third-party-notices-check.yaml @@ -12,6 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +# Regenerates THIRD_PARTY_NOTICES.md and fails if it differs from the committed +# copy, so a dependency change cannot land without refreshed attribution. The +# generator also fails when a license file has no verified URL in +# hack/license-urls.tsv, which catches a bump that skipped +# 'make third-party-notices-urls'. Link rot is caught separately by +# third-party-notices-links.yaml. name: Third-Party Notices diff --git a/.github/workflows/third-party-notices-links.yaml b/.github/workflows/third-party-notices-links.yaml new file mode 100644 index 000000000..bffd225ec --- /dev/null +++ b/.github/workflows/third-party-notices-links.yaml @@ -0,0 +1,62 @@ +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Re-verifies every license URL against the vendored bytes. Links are proven +# correct when written, but upstream can retag, rename or archive a repository +# afterwards, and no offline gate can see that. This runs on a schedule rather +# than per pull request so link rot does not block unrelated work. + +name: Third-Party Notices Link Check + +on: + schedule: + - cron: '0 6 * * 1' + workflow_dispatch: + +permissions: + contents: read + +jobs: + verify-links: + name: Re-verify license URLs against upstream + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - name: Check out code + uses: actions/checkout@v7 + + - name: Get Golang Version + id: golang_version + run: | + GOLANG_VERSION=$(./hack/golang-version.sh) + echo "Detected $GOLANG_VERSION" + echo "golang_version=${GOLANG_VERSION}" >> $GITHUB_OUTPUT + + - name: Install Go + uses: actions/setup-go@v7 + with: + go-version: ${{ steps.golang_version.outputs.golang_version }} + + - name: Re-verify every license URL + env: + URLS_OUTPUT: /tmp/license-urls-fresh.tsv + run: make bin/go-licenses && bash hack/verify-license-urls.sh + + - name: Compare against the committed map + run: | + if ! diff -u <(LC_ALL=C grep -v '^#' hack/license-urls.tsv) \ + <(LC_ALL=C grep -v '^#' /tmp/license-urls-fresh.tsv); then + echo "::error::A license URL no longer serves the vendored bytes. Upstream may have retagged or moved." + exit 1 + fi diff --git a/Makefile b/Makefile index cabf477ad..8009f4f55 100644 --- a/Makefile +++ b/Makefile @@ -29,8 +29,8 @@ EXAMPLE_TARGETS := $(patsubst %,example-%, $(EXAMPLES)) CMDS := $(patsubst ./cmd/%/,%,$(sort $(dir $(wildcard ./cmd/*/)))) CMD_TARGETS := $(patsubst %,cmd-%, $(CMDS)) -CHECK_TARGETS := lint -MAKE_TARGETS := binaries build check fmt lint-internal test examples cmds coverage generate vendor check-modules third-party-notices check-third-party-notices $(CHECK_TARGETS) +CHECK_TARGETS := lint test-tools +MAKE_TARGETS := binaries build check fmt lint-internal test examples cmds coverage generate vendor check-modules third-party-notices check-third-party-notices third-party-notices-repos third-party-notices-urls $(CHECK_TARGETS) TARGETS := $(MAKE_TARGETS) $(EXAMPLE_TARGETS) $(CMD_TARGETS) @@ -129,6 +129,21 @@ check-third-party-notices: third-party-notices @git diff --exit-code -- THIRD_PARTY_NOTICES.md \ || { echo "ERROR: THIRD_PARTY_NOTICES.md is stale. Run 'make third-party-notices' and commit the change."; exit 1; } +# Needs network. Rarely run: keyed by module, so a version bump does not +# invalidate it. Only a new dependency does. +third-party-notices-repos: + @bash hack/resolve-module-repos.sh + +# Needs network. Every URL is content-verified against the vendored copy before +# it is written, so re-run this whenever a dependency version changes. +third-party-notices-urls: bin/go-licenses third-party-notices-repos + @bash hack/verify-license-urls.sh + +test-tools: + @for t in hack/*_test.sh; do \ + bash "$$t" || exit 1; \ + done + COVERAGE_FILE := coverage.out test: build cmds go test -coverprofile=$(COVERAGE_FILE) $(MODULE)/cmd/... $(MODULE)/internal/... $(MODULE)/api/... diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index a4e10747f..3755a3762 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -11,6 +11,13 @@ platform. The `nvidia-device-plugin`, `gpu-feature-discovery`, `k8s-device-plugin` image. Go standard library packages are excluded; they are covered by the license of the Go distribution itself. +Each dependency is listed with the version redistributed and a link to the +license file in that version's upstream source. Every link was verified by +fetching it and comparing its contents against the copy vendored here, so each +one resolves to the same license text reproduced below. Modules that no command +under `cmd/` links are not listed; those are vendored only for this module's own +tests and build tooling. + The `k8s-device-plugin` image uses `nvcr.io/nvidia/distroless/go` as a base image. All of the OSS packages and source included in this image can be found at . A statically @@ -18,92 +25,94 @@ compiled busybox binary is added to the image, which is licensed under GPLv2. ## Dependency Index -| Package | License | Dependency | -|---------|---------|------------| -| `github.com/NVIDIA/go-gpuallocator` | Apache-2.0 | `github.com/NVIDIA/go-gpuallocator` | -| `github.com/NVIDIA/go-nvlib/pkg` | Apache-2.0 | `github.com/NVIDIA/go-nvlib` | -| `github.com/NVIDIA/go-nvml/pkg` | Apache-2.0 | `github.com/NVIDIA/go-nvml` | -| `github.com/NVIDIA/nvidia-container-toolkit` | Apache-2.0 | `github.com/NVIDIA/nvidia-container-toolkit` | -| `github.com/cpuguy83/go-md2man/v2/md2man` | MIT | `github.com/cpuguy83/go-md2man/v2` | -| `github.com/cyphar/filepath-securejoin` | BSD-3-Clause / MPL-2.0 | `github.com/cyphar/filepath-securejoin` | -| `github.com/davecgh/go-spew/spew` | ISC | `github.com/davecgh/go-spew` | -| `github.com/emicklei/go-restful/v3` | MIT | `github.com/emicklei/go-restful/v3` | -| `github.com/fsnotify/fsnotify` | BSD-3-Clause | `github.com/fsnotify/fsnotify` | -| `github.com/fxamacker/cbor/v2` | MIT | `github.com/fxamacker/cbor/v2` | -| `github.com/go-logr/logr` | Apache-2.0 | `github.com/go-logr/logr` | -| `github.com/go-openapi/jsonpointer` | Apache-2.0 | `github.com/go-openapi/jsonpointer` | -| `github.com/go-openapi/jsonreference` | Apache-2.0 | `github.com/go-openapi/jsonreference` | -| `github.com/go-openapi/swag` | Apache-2.0 | `github.com/go-openapi/swag` | -| `github.com/google/gnostic-models` | Apache-2.0 | `github.com/google/gnostic-models` | -| `github.com/google/renameio` | Apache-2.0 | `github.com/google/renameio` | -| `github.com/google/uuid` | BSD-3-Clause | `github.com/google/uuid` | -| `github.com/josharian/intern` | MIT | `github.com/josharian/intern` | -| `github.com/json-iterator/go` | MIT | `github.com/json-iterator/go` | -| `github.com/mailru/easyjson` | MIT | `github.com/mailru/easyjson` | -| `github.com/moby/sys/capability` | BSD-2-Clause | `github.com/moby/sys/capability` | -| `github.com/moby/sys/devices` | Apache-2.0 | `github.com/moby/sys/devices` | -| `github.com/moby/sys/mountinfo` | Apache-2.0 | `github.com/moby/sys/mountinfo` | -| `github.com/modern-go/concurrent` | Apache-2.0 | `github.com/modern-go/concurrent` | -| `github.com/modern-go/reflect2` | Apache-2.0 | `github.com/modern-go/reflect2` | -| `github.com/munnerz/goautoneg` | BSD-3-Clause | `github.com/munnerz/goautoneg` | -| `github.com/opencontainers/cgroups/devices/config` | Apache-2.0 | `github.com/opencontainers/cgroups` | -| `github.com/opencontainers/runc/libcontainer/devices` | Apache-2.0 | `github.com/opencontainers/runc` | -| `github.com/opencontainers/runtime-spec/specs-go` | Apache-2.0 | `github.com/opencontainers/runtime-spec` | -| `github.com/opencontainers/runtime-tools` | Apache-2.0 | `github.com/opencontainers/runtime-tools` | -| `github.com/opencontainers/selinux` | Apache-2.0 | `github.com/opencontainers/selinux` | -| `github.com/pmezard/go-difflib/difflib` | BSD-3-Clause | `github.com/pmezard/go-difflib` | -| `github.com/prometheus/procfs` | Apache-2.0 | `github.com/prometheus/procfs` | -| `github.com/russross/blackfriday/v2` | BSD-2-Clause | `github.com/russross/blackfriday/v2` | -| `github.com/sirupsen/logrus` | MIT | `github.com/sirupsen/logrus` | -| `github.com/spf13/pflag` | BSD-3-Clause | `github.com/spf13/pflag` | -| `github.com/urfave/cli/v2` | MIT | `github.com/urfave/cli/v2` | -| `github.com/x448/float16` | MIT | `github.com/x448/float16` | -| `github.com/xrash/smetrics` | MIT | `github.com/xrash/smetrics` | -| `go.yaml.in/yaml/v2` | Apache-2.0 | `go.yaml.in/yaml/v2` | -| `go.yaml.in/yaml/v3` | MIT | `go.yaml.in/yaml/v3` | -| `golang.org/x/mod/semver` | BSD-3-Clause | `golang.org/x/mod` | -| `golang.org/x/net` | BSD-3-Clause | `golang.org/x/net` | -| `golang.org/x/oauth2` | BSD-3-Clause | `golang.org/x/oauth2` | -| `golang.org/x/sys/unix` | BSD-3-Clause | `golang.org/x/sys` | -| `golang.org/x/term` | BSD-3-Clause | `golang.org/x/term` | -| `golang.org/x/text` | BSD-3-Clause | `golang.org/x/text` | -| `golang.org/x/time/rate` | BSD-3-Clause | `golang.org/x/time` | -| `google.golang.org/genproto/googleapis/rpc/status` | Apache-2.0 | `google.golang.org/genproto/googleapis/rpc` | -| `google.golang.org/grpc` | Apache-2.0 | `google.golang.org/grpc` | -| `google.golang.org/protobuf` | BSD-3-Clause | `google.golang.org/protobuf` | -| `gopkg.in/evanphx/json-patch.v4` | BSD-3-Clause | `gopkg.in/evanphx/json-patch.v4` | -| `gopkg.in/inf.v0` | BSD-3-Clause | `gopkg.in/inf.v0` | -| `gopkg.in/yaml.v3` | MIT | `gopkg.in/yaml.v3` | -| `k8s.io/api` | Apache-2.0 | `k8s.io/api` | -| `k8s.io/apimachinery/pkg` | Apache-2.0 | `k8s.io/apimachinery` | -| `k8s.io/apimachinery/third_party/forked/golang` | BSD-3-Clause | `k8s.io/apimachinery` | -| `k8s.io/client-go` | Apache-2.0 | `k8s.io/client-go` | -| `k8s.io/klog/v2` | Apache-2.0 | `k8s.io/klog/v2` | -| `k8s.io/kube-openapi/pkg` | Apache-2.0 | `k8s.io/kube-openapi` | -| `k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json` | BSD-3-Clause | `k8s.io/kube-openapi` | -| `k8s.io/kube-openapi/pkg/validation/spec` | Apache-2.0 | `k8s.io/kube-openapi` | -| `k8s.io/kubelet/pkg/apis/deviceplugin/v1beta1` | Apache-2.0 | `k8s.io/kubelet` | -| `k8s.io/mount-utils` | Apache-2.0 | `k8s.io/mount-utils` | -| `k8s.io/utils` | Apache-2.0 | `k8s.io/utils` | -| `k8s.io/utils/internal/third_party/forked/golang/net` | BSD-3-Clause | `k8s.io/utils` | -| `sigs.k8s.io/json` | Apache-2.0 / BSD-3-Clause | `sigs.k8s.io/json` | -| `sigs.k8s.io/node-feature-discovery/api/generated` | Apache-2.0 | `sigs.k8s.io/node-feature-discovery` | -| `sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1` | Apache-2.0 | `sigs.k8s.io/node-feature-discovery/api/nfd` | -| `sigs.k8s.io/randfill` | Apache-2.0 | `sigs.k8s.io/randfill` | -| `sigs.k8s.io/structured-merge-diff/v6` | Apache-2.0 | `sigs.k8s.io/structured-merge-diff/v6` | -| `sigs.k8s.io/yaml` | Apache-2.0 / BSD-3-Clause / MIT | `sigs.k8s.io/yaml` | -| `tags.cncf.io/container-device-interface` | Apache-2.0 | `tags.cncf.io/container-device-interface` | -| `tags.cncf.io/container-device-interface/specs-go` | Apache-2.0 | `tags.cncf.io/container-device-interface/specs-go` | +| Package | Version | License | Location | +|---------|---------|---------|----------| +| `github.com/NVIDIA/go-gpuallocator` | v0.6.0 | Apache-2.0 | [LICENSE](https://github.com/NVIDIA/go-gpuallocator/blob/v0.6.0/LICENSE) | +| `github.com/NVIDIA/go-nvlib/pkg` | v0.12.0 | Apache-2.0 | [LICENSE](https://github.com/NVIDIA/go-nvlib/blob/v0.12.0/LICENSE) / [NOTICE](https://github.com/NVIDIA/go-nvlib/blob/v0.12.0/NOTICE) | +| `github.com/NVIDIA/go-nvml/pkg` | v0.13.3-1 | Apache-2.0 | [LICENSE](https://github.com/NVIDIA/go-nvml/blob/v0.13.3-1/LICENSE) | +| `github.com/NVIDIA/nvidia-container-toolkit` | v1.20.0 | Apache-2.0 | [LICENSE](https://github.com/NVIDIA/nvidia-container-toolkit/blob/v1.20.0/LICENSE) | +| `github.com/cpuguy83/go-md2man/v2/md2man` | v2.0.7 | MIT | [LICENSE.md](https://github.com/cpuguy83/go-md2man/blob/v2.0.7/LICENSE.md) | +| `github.com/cyphar/filepath-securejoin` | v0.7.0 | BSD-3-Clause / MPL-2.0 | [COPYING.md](https://github.com/cyphar/filepath-securejoin/blob/v0.7.0/COPYING.md) / [LICENSE.BSD](https://github.com/cyphar/filepath-securejoin/blob/v0.7.0/LICENSE.BSD) / [LICENSE.MPL-2.0](https://github.com/cyphar/filepath-securejoin/blob/v0.7.0/LICENSE.MPL-2.0) | +| `github.com/davecgh/go-spew/spew` | v1.1.2-0.20180830191138-d8f796af33cc | ISC | [LICENSE](https://github.com/davecgh/go-spew/blob/d8f796af33cc/LICENSE) | +| `github.com/emicklei/go-restful/v3` | v3.13.0 | MIT | [LICENSE](https://github.com/emicklei/go-restful/blob/v3.13.0/LICENSE) | +| `github.com/fsnotify/fsnotify` | v1.10.1 | BSD-3-Clause | [LICENSE](https://github.com/fsnotify/fsnotify/blob/v1.10.1/LICENSE) | +| `github.com/fxamacker/cbor/v2` | v2.9.0 | MIT | [LICENSE](https://github.com/fxamacker/cbor/blob/v2.9.0/LICENSE) | +| `github.com/go-logr/logr` | v1.4.3 | Apache-2.0 | [LICENSE](https://github.com/go-logr/logr/blob/v1.4.3/LICENSE) | +| `github.com/go-openapi/jsonpointer` | v0.21.0 | Apache-2.0 | [LICENSE](https://github.com/go-openapi/jsonpointer/blob/v0.21.0/LICENSE) | +| `github.com/go-openapi/jsonreference` | v0.20.4 | Apache-2.0 | [LICENSE](https://github.com/go-openapi/jsonreference/blob/v0.20.4/LICENSE) | +| `github.com/go-openapi/swag` | v0.23.0 | Apache-2.0 | [LICENSE](https://github.com/go-openapi/swag/blob/v0.23.0/LICENSE) | +| `github.com/google/gnostic-models` | v0.7.0 | Apache-2.0 | [LICENSE](https://github.com/google/gnostic-models/blob/v0.7.0/LICENSE) | +| `github.com/google/renameio` | v1.0.1 | Apache-2.0 | [LICENSE](https://github.com/google/renameio/blob/v1.0.1/LICENSE) | +| `github.com/google/uuid` | v1.6.0 | BSD-3-Clause | [LICENSE](https://github.com/google/uuid/blob/v1.6.0/LICENSE) | +| `github.com/josharian/intern` | v1.0.0 | MIT | [license.md](https://github.com/josharian/intern/blob/v1.0.0/license.md) | +| `github.com/json-iterator/go` | v1.1.12 | MIT | [LICENSE](https://github.com/json-iterator/go/blob/v1.1.12/LICENSE) | +| `github.com/mailru/easyjson` | v0.7.7 | MIT | [LICENSE](https://github.com/mailru/easyjson/blob/v0.7.7/LICENSE) | +| `github.com/moby/sys/capability` | v0.4.0 | BSD-2-Clause | [LICENSE](https://github.com/moby/sys/blob/capability/v0.4.0/capability/LICENSE) | +| `github.com/moby/sys/devices` | v0.1.0 | Apache-2.0 | [LICENSE](https://github.com/moby/sys/blob/devices/v0.1.0/LICENSE) | +| `github.com/moby/sys/mountinfo` | v0.7.2 | Apache-2.0 | [LICENSE](https://github.com/moby/sys/blob/mountinfo/v0.7.2/LICENSE) | +| `github.com/modern-go/concurrent` | v0.0.0-20180306012644-bacd9c7ef1dd | Apache-2.0 | [LICENSE](https://github.com/modern-go/concurrent/blob/bacd9c7ef1dd/LICENSE) | +| `github.com/modern-go/reflect2` | v1.0.3-0.20250322232337-35a7c28c31ee | Apache-2.0 | [LICENSE](https://github.com/modern-go/reflect2/blob/35a7c28c31ee/LICENSE) | +| `github.com/munnerz/goautoneg` | v0.0.0-20191010083416-a7dc8b61c822 | BSD-3-Clause | [LICENSE](https://github.com/munnerz/goautoneg/blob/a7dc8b61c822/LICENSE) | +| `github.com/opencontainers/cgroups/devices/config` | v0.0.7 | Apache-2.0 | [LICENSE](https://github.com/opencontainers/cgroups/blob/v0.0.7/LICENSE) | +| `github.com/opencontainers/runc/libcontainer/devices` | v1.5.0 | Apache-2.0 | [LICENSE](https://github.com/opencontainers/runc/blob/v1.5.0/LICENSE) / [NOTICE](https://github.com/opencontainers/runc/blob/v1.5.0/NOTICE) | +| `github.com/opencontainers/runtime-spec/specs-go` | v1.3.0 | Apache-2.0 | [LICENSE](https://github.com/opencontainers/runtime-spec/blob/v1.3.0/LICENSE) | +| `github.com/opencontainers/runtime-tools` | v0.9.1-0.20251114084447-edf4cb3d2116 | Apache-2.0 | [LICENSE](https://github.com/opencontainers/runtime-tools/blob/edf4cb3d2116/LICENSE) | +| `github.com/opencontainers/selinux` | v1.15.1 | Apache-2.0 | [LICENSE](https://github.com/opencontainers/selinux/blob/v1.15.1/LICENSE) | +| `github.com/pmezard/go-difflib/difflib` | v1.0.1-0.20181226105442-5d4384ee4fb2 | BSD-3-Clause | [LICENSE](https://github.com/pmezard/go-difflib/blob/5d4384ee4fb2/LICENSE) | +| `github.com/prometheus/procfs` | v0.21.1 | Apache-2.0 | [LICENSE](https://github.com/prometheus/procfs/blob/v0.21.1/LICENSE) / [NOTICE](https://github.com/prometheus/procfs/blob/v0.21.1/NOTICE) | +| `github.com/russross/blackfriday/v2` | v2.1.0 | BSD-2-Clause | [LICENSE.txt](https://github.com/russross/blackfriday/blob/v2.1.0/LICENSE.txt) | +| `github.com/sirupsen/logrus` | v1.10.0 | MIT | [LICENSE](https://github.com/sirupsen/logrus/blob/v1.10.0/LICENSE) | +| `github.com/spf13/pflag` | v1.0.10 | BSD-3-Clause | [LICENSE](https://github.com/spf13/pflag/blob/v1.0.10/LICENSE) | +| `github.com/urfave/cli/v2` | v2.27.7 | MIT | [LICENSE](https://github.com/urfave/cli/blob/v2.27.7/LICENSE) | +| `github.com/x448/float16` | v0.8.4 | MIT | [LICENSE](https://github.com/x448/float16/blob/v0.8.4/LICENSE) | +| `github.com/xrash/smetrics` | v0.0.0-20240521201337-686a1a2994c1 | MIT | [LICENSE](https://github.com/xrash/smetrics/blob/686a1a2994c1/LICENSE) | +| `go.yaml.in/yaml/v2` | v2.4.3 | Apache-2.0 / MIT | [LICENSE](https://github.com/yaml/go-yaml/blob/v2.4.3/LICENSE) / [LICENSE.libyaml](https://github.com/yaml/go-yaml/blob/v2.4.3/LICENSE.libyaml) / [NOTICE](https://github.com/yaml/go-yaml/blob/v2.4.3/NOTICE) | +| `go.yaml.in/yaml/v3` | v3.0.4 | Apache-2.0 / MIT | [LICENSE](https://github.com/yaml/go-yaml/blob/v3.0.4/LICENSE) / [NOTICE](https://github.com/yaml/go-yaml/blob/v3.0.4/NOTICE) | +| `golang.org/x/mod/semver` | v0.40.0 | BSD-3-Clause | [LICENSE](https://go.googlesource.com/mod/+/refs/tags/v0.40.0/LICENSE) / [PATENTS](https://go.googlesource.com/mod/+/refs/tags/v0.40.0/PATENTS) | +| `golang.org/x/net` | v0.56.0 | BSD-3-Clause | [LICENSE](https://go.googlesource.com/net/+/refs/tags/v0.56.0/LICENSE) / [PATENTS](https://go.googlesource.com/net/+/refs/tags/v0.56.0/PATENTS) | +| `golang.org/x/oauth2` | v0.36.0 | BSD-3-Clause | [LICENSE](https://go.googlesource.com/oauth2/+/refs/tags/v0.36.0/LICENSE) | +| `golang.org/x/sys/unix` | v0.47.0 | BSD-3-Clause | [LICENSE](https://go.googlesource.com/sys/+/refs/tags/v0.47.0/LICENSE) / [PATENTS](https://go.googlesource.com/sys/+/refs/tags/v0.47.0/PATENTS) | +| `golang.org/x/term` | v0.44.0 | BSD-3-Clause | [LICENSE](https://go.googlesource.com/term/+/refs/tags/v0.44.0/LICENSE) / [PATENTS](https://go.googlesource.com/term/+/refs/tags/v0.44.0/PATENTS) | +| `golang.org/x/text` | v0.41.0 | BSD-3-Clause | [LICENSE](https://go.googlesource.com/text/+/refs/tags/v0.41.0/LICENSE) / [PATENTS](https://go.googlesource.com/text/+/refs/tags/v0.41.0/PATENTS) | +| `golang.org/x/time/rate` | v0.15.0 | BSD-3-Clause | [LICENSE](https://go.googlesource.com/time/+/refs/tags/v0.15.0/LICENSE) / [PATENTS](https://go.googlesource.com/time/+/refs/tags/v0.15.0/PATENTS) | +| `google.golang.org/genproto/googleapis/rpc/status` | v0.0.0-20260526163538-3dc84a4a5aaa | Apache-2.0 | [LICENSE](https://github.com/googleapis/go-genproto/blob/3dc84a4a5aaa/LICENSE) | +| `google.golang.org/grpc` | v1.83.1 | Apache-2.0 | [AUTHORS](https://github.com/grpc/grpc-go/blob/v1.83.1/AUTHORS) / [LICENSE](https://github.com/grpc/grpc-go/blob/v1.83.1/LICENSE) / [NOTICE.txt](https://github.com/grpc/grpc-go/blob/v1.83.1/NOTICE.txt) | +| `google.golang.org/protobuf` | v1.36.12-0.20260120151049-f2248ac996af | BSD-3-Clause | [LICENSE](https://go.googlesource.com/protobuf/+/f2248ac996af/LICENSE) / [PATENTS](https://go.googlesource.com/protobuf/+/f2248ac996af/PATENTS) | +| `gopkg.in/evanphx/json-patch.v4` | v4.13.0 | BSD-3-Clause | [LICENSE](https://github.com/evanphx/json-patch/blob/v4.13.0/LICENSE) | +| `gopkg.in/inf.v0` | v0.9.1 | BSD-3-Clause | [LICENSE](https://github.com/go-inf/inf/blob/v0.9.1/LICENSE) | +| `gopkg.in/yaml.v3` | v3.0.1 | Apache-2.0 / MIT | [LICENSE](https://github.com/go-yaml/yaml/blob/v3.0.1/LICENSE) / [NOTICE](https://github.com/go-yaml/yaml/blob/v3.0.1/NOTICE) | +| `k8s.io/api` | v0.36.3 | Apache-2.0 | [LICENSE](https://github.com/kubernetes/api/blob/v0.36.3/LICENSE) | +| `k8s.io/apimachinery/pkg` | v0.36.3 | Apache-2.0 | [LICENSE](https://github.com/kubernetes/apimachinery/blob/v0.36.3/LICENSE) | +| `k8s.io/apimachinery/third_party/forked/golang` | v0.36.3 | BSD-3-Clause | [LICENSE](https://github.com/kubernetes/apimachinery/blob/v0.36.3/third_party/forked/golang/LICENSE) / [PATENTS](https://github.com/kubernetes/apimachinery/blob/v0.36.3/third_party/forked/golang/PATENTS) | +| `k8s.io/client-go` | v0.36.3 | Apache-2.0 | [LICENSE](https://github.com/kubernetes/client-go/blob/v0.36.3/LICENSE) | +| `k8s.io/klog/v2` | v2.140.0 | Apache-2.0 | [LICENSE](https://github.com/kubernetes/klog/blob/v2.140.0/LICENSE) | +| `k8s.io/kube-openapi/pkg` | v0.0.0-20260317180543-43fb72c5454a | Apache-2.0 | [LICENSE](https://github.com/kubernetes/kube-openapi/blob/43fb72c5454a/LICENSE) | +| `k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json` | v0.0.0-20260317180543-43fb72c5454a | BSD-3-Clause | [AUTHORS](https://github.com/kubernetes/kube-openapi/blob/43fb72c5454a/pkg/internal/third_party/go-json-experiment/json/AUTHORS) / [LICENSE](https://github.com/kubernetes/kube-openapi/blob/43fb72c5454a/pkg/internal/third_party/go-json-experiment/json/LICENSE) | +| `k8s.io/kube-openapi/pkg/validation/spec` | v0.0.0-20260317180543-43fb72c5454a | Apache-2.0 | [LICENSE](https://github.com/kubernetes/kube-openapi/blob/43fb72c5454a/pkg/validation/spec/LICENSE) | +| `k8s.io/kubelet/pkg/apis/deviceplugin/v1beta1` | v0.36.3 | Apache-2.0 | [LICENSE](https://github.com/kubernetes/kubelet/blob/v0.36.3/LICENSE) | +| `k8s.io/mount-utils` | v0.36.3 | Apache-2.0 | [LICENSE](https://github.com/kubernetes/mount-utils/blob/v0.36.3/LICENSE) | +| `k8s.io/utils` | v0.0.0-20260210185600-b8788abfbbc2 | Apache-2.0 | [LICENSE](https://github.com/kubernetes/utils/blob/b8788abfbbc2/LICENSE) | +| `k8s.io/utils/internal/third_party/forked/golang/net` | v0.0.0-20260210185600-b8788abfbbc2 | BSD-3-Clause | [LICENSE](https://github.com/kubernetes/utils/blob/b8788abfbbc2/internal/third_party/forked/golang/LICENSE) / [PATENTS](https://github.com/kubernetes/utils/blob/b8788abfbbc2/internal/third_party/forked/golang/PATENTS) | +| `sigs.k8s.io/json` | v0.0.0-20250730193827-2d320260d730 | Apache-2.0 / BSD-3-Clause | [LICENSE](https://github.com/kubernetes-sigs/json/blob/2d320260d730/LICENSE) | +| `sigs.k8s.io/node-feature-discovery/api/generated` | v0.19.0 | Apache-2.0 | [LICENSE](https://github.com/kubernetes-sigs/node-feature-discovery/blob/v0.19.0/LICENSE) | +| `sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1` | v0.19.0 | Apache-2.0 | [LICENSE](https://github.com/kubernetes-sigs/node-feature-discovery/blob/api/nfd/v0.19.0/LICENSE) | +| `sigs.k8s.io/randfill` | v1.0.0 | Apache-2.0 | [LICENSE](https://github.com/kubernetes-sigs/randfill/blob/v1.0.0/LICENSE) / [NOTICE](https://github.com/kubernetes-sigs/randfill/blob/v1.0.0/NOTICE) | +| `sigs.k8s.io/structured-merge-diff/v6` | v6.4.0 | Apache-2.0 | [LICENSE](https://github.com/kubernetes-sigs/structured-merge-diff/blob/v6.4.0/LICENSE) | +| `sigs.k8s.io/yaml` | v1.6.0 | Apache-2.0 / BSD-3-Clause / MIT | [LICENSE](https://github.com/kubernetes-sigs/yaml/blob/v1.6.0/LICENSE) | +| `tags.cncf.io/container-device-interface` | v1.1.0 | Apache-2.0 | [LICENSE](https://github.com/cncf-tags/container-device-interface/blob/v1.1.0/LICENSE) | +| `tags.cncf.io/container-device-interface/specs-go` | v1.1.0 | Apache-2.0 | [LICENSE](https://github.com/cncf-tags/container-device-interface/blob/specs-go/v1.1.0/LICENSE) | ## License Texts ### github.com/NVIDIA/go-gpuallocator +* Version: v0.6.0 * License: Apache-2.0 -* Module: github.com/NVIDIA/go-gpuallocator #### LICENSE + + ```text Apache License @@ -313,11 +322,13 @@ compiled busybox binary is added to the image, which is licensed under GPLv2. ### github.com/NVIDIA/go-nvlib/pkg +* Version: v0.12.0 * License: Apache-2.0 -* Module: github.com/NVIDIA/go-nvlib #### LICENSE + + ```text Apache License @@ -526,6 +537,8 @@ compiled busybox binary is added to the image, which is licensed under GPLv2. #### NOTICE + + ```text The file pkg/pciids/default_pci.ids is distributed under the 3-clause BSD License. Maintained by Albert Pool, Martin Mares, and other volunteers from @@ -537,11 +550,13 @@ the PCI ID Project at https://pci-ids.ucw.cz/. ### github.com/NVIDIA/go-nvml/pkg +* Version: v0.13.3-1 * License: Apache-2.0 -* Module: github.com/NVIDIA/go-nvml #### LICENSE + + ```text Apache License @@ -751,11 +766,13 @@ the PCI ID Project at https://pci-ids.ucw.cz/. ### github.com/NVIDIA/nvidia-container-toolkit +* Version: v1.20.0 * License: Apache-2.0 -* Module: github.com/NVIDIA/nvidia-container-toolkit #### LICENSE + + ```text Apache License @@ -965,11 +982,13 @@ the PCI ID Project at https://pci-ids.ucw.cz/. ### github.com/cpuguy83/go-md2man/v2/md2man +* Version: v2.0.7 * License: MIT -* Module: github.com/cpuguy83/go-md2man/v2 #### LICENSE.md + + ```text The MIT License (MIT) @@ -998,11 +1017,13 @@ SOFTWARE. ### github.com/cyphar/filepath-securejoin +* Version: v0.7.0 * License: BSD-3-Clause / MPL-2.0 -* Module: github.com/cyphar/filepath-securejoin #### COPYING.md + + ````text ## COPYING ## @@ -1456,6 +1477,8 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice #### LICENSE.BSD + + ```text Copyright (C) 2014-2015 Docker Inc & Go Authors. All rights reserved. Copyright (C) 2017-2024 SUSE LLC. All rights reserved. @@ -1490,6 +1513,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #### LICENSE.MPL-2.0 + + ```text Mozilla Public License Version 2.0 ================================== @@ -1870,11 +1895,13 @@ Exhibit B - "Incompatible With Secondary Licenses" Notice ### github.com/davecgh/go-spew/spew +* Version: v1.1.2-0.20180830191138-d8f796af33cc * License: ISC -* Module: github.com/davecgh/go-spew #### LICENSE + + ```text ISC License @@ -1897,11 +1924,13 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ### github.com/emicklei/go-restful/v3 +* Version: v3.13.0 * License: MIT -* Module: github.com/emicklei/go-restful/v3 #### LICENSE + + ```text Copyright (c) 2012,2013 Ernest Micklei @@ -1930,11 +1959,13 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ### github.com/fsnotify/fsnotify +* Version: v1.10.1 * License: BSD-3-Clause -* Module: github.com/fsnotify/fsnotify #### LICENSE + + ```text Copyright © 2012 The Go Authors. All rights reserved. Copyright © fsnotify Authors. All rights reserved. @@ -1967,11 +1998,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### github.com/fxamacker/cbor/v2 +* Version: v2.9.0 * License: MIT -* Module: github.com/fxamacker/cbor/v2 #### LICENSE + + ```text MIT License @@ -1999,11 +2032,13 @@ SOFTWARE. ### github.com/go-logr/logr +* Version: v1.4.3 * License: Apache-2.0 -* Module: github.com/go-logr/logr #### LICENSE + + ```text Apache License Version 2.0, January 2004 @@ -2212,11 +2247,13 @@ SOFTWARE. ### github.com/go-openapi/jsonpointer +* Version: v0.21.0 * License: Apache-2.0 -* Module: github.com/go-openapi/jsonpointer #### LICENSE + + ```text Apache License @@ -2426,11 +2463,13 @@ SOFTWARE. ### github.com/go-openapi/jsonreference +* Version: v0.20.4 * License: Apache-2.0 -* Module: github.com/go-openapi/jsonreference #### LICENSE + + ```text Apache License @@ -2640,11 +2679,13 @@ SOFTWARE. ### github.com/go-openapi/swag +* Version: v0.23.0 * License: Apache-2.0 -* Module: github.com/go-openapi/swag #### LICENSE + + ```text Apache License @@ -2854,11 +2895,13 @@ SOFTWARE. ### github.com/google/gnostic-models +* Version: v0.7.0 * License: Apache-2.0 -* Module: github.com/google/gnostic-models #### LICENSE + + ```text Apache License @@ -3069,11 +3112,13 @@ SOFTWARE. ### github.com/google/renameio +* Version: v1.0.1 * License: Apache-2.0 -* Module: github.com/google/renameio #### LICENSE + + ```text Apache License @@ -3283,11 +3328,13 @@ SOFTWARE. ### github.com/google/uuid +* Version: v1.6.0 * License: BSD-3-Clause -* Module: github.com/google/uuid #### LICENSE + + ```text Copyright (c) 2009,2014 Google Inc. All rights reserved. @@ -3322,11 +3369,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### github.com/josharian/intern +* Version: v1.0.0 * License: MIT -* Module: github.com/josharian/intern #### license.md + + ```text MIT License @@ -3355,11 +3404,13 @@ SOFTWARE. ### github.com/json-iterator/go +* Version: v1.1.12 * License: MIT -* Module: github.com/json-iterator/go #### LICENSE + + ```text MIT License @@ -3388,11 +3439,13 @@ SOFTWARE. ### github.com/mailru/easyjson +* Version: v0.7.7 * License: MIT -* Module: github.com/mailru/easyjson #### LICENSE + + ```text Copyright (c) 2016 Mail.Ru Group @@ -3407,11 +3460,13 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI ### github.com/moby/sys/capability +* Version: v0.4.0 * License: BSD-2-Clause -* Module: github.com/moby/sys/capability #### LICENSE + + ```text Copyright 2023 The Capability Authors. Copyright 2013 Suryandaru Triandana @@ -3444,11 +3499,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### github.com/moby/sys/devices +* Version: v0.1.0 * License: Apache-2.0 -* Module: github.com/moby/sys/devices #### LICENSE + + ```text Apache License @@ -3658,11 +3715,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### github.com/moby/sys/mountinfo +* Version: v0.7.2 * License: Apache-2.0 -* Module: github.com/moby/sys/mountinfo #### LICENSE + + ```text Apache License @@ -3872,11 +3931,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### github.com/modern-go/concurrent +* Version: v0.0.0-20180306012644-bacd9c7ef1dd * License: Apache-2.0 -* Module: github.com/modern-go/concurrent #### LICENSE + + ```text Apache License Version 2.0, January 2004 @@ -4085,11 +4146,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### github.com/modern-go/reflect2 +* Version: v1.0.3-0.20250322232337-35a7c28c31ee * License: Apache-2.0 -* Module: github.com/modern-go/reflect2 #### LICENSE + + ```text Apache License Version 2.0, January 2004 @@ -4298,11 +4361,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### github.com/munnerz/goautoneg +* Version: v0.0.0-20191010083416-a7dc8b61c822 * License: BSD-3-Clause -* Module: github.com/munnerz/goautoneg #### LICENSE + + ```text Copyright (c) 2011, Open Knowledge Foundation Ltd. All rights reserved. @@ -4341,11 +4406,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### github.com/opencontainers/cgroups/devices/config +* Version: v0.0.7 * License: Apache-2.0 -* Module: github.com/opencontainers/cgroups #### LICENSE + + ```text Apache License Version 2.0, January 2004 @@ -4554,11 +4621,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### github.com/opencontainers/runc/libcontainer/devices +* Version: v1.5.0 * License: Apache-2.0 -* Module: github.com/opencontainers/runc #### LICENSE + + ```text Apache License @@ -4756,6 +4825,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #### NOTICE + + ```text runc @@ -4780,11 +4851,13 @@ See also http://www.apache.org/dev/crypto.html and/or seek legal counsel. ### github.com/opencontainers/runtime-spec/specs-go +* Version: v1.3.0 * License: Apache-2.0 -* Module: github.com/opencontainers/runtime-spec #### LICENSE + + ```text Apache License @@ -4983,11 +5056,13 @@ See also http://www.apache.org/dev/crypto.html and/or seek legal counsel. ### github.com/opencontainers/runtime-tools +* Version: v0.9.1-0.20251114084447-edf4cb3d2116 * License: Apache-2.0 -* Module: github.com/opencontainers/runtime-tools #### LICENSE + + ```text Apache License @@ -5186,11 +5261,13 @@ See also http://www.apache.org/dev/crypto.html and/or seek legal counsel. ### github.com/opencontainers/selinux +* Version: v1.15.1 * License: Apache-2.0 -* Module: github.com/opencontainers/selinux #### LICENSE + + ```text Apache License Version 2.0, January 2004 @@ -5399,11 +5476,13 @@ See also http://www.apache.org/dev/crypto.html and/or seek legal counsel. ### github.com/pmezard/go-difflib/difflib +* Version: v1.0.1-0.20181226105442-5d4384ee4fb2 * License: BSD-3-Clause -* Module: github.com/pmezard/go-difflib #### LICENSE + + ```text Copyright (c) 2013, Patrick Mezard All rights reserved. @@ -5438,11 +5517,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### github.com/prometheus/procfs +* Version: v0.21.1 * License: Apache-2.0 -* Module: github.com/prometheus/procfs #### LICENSE + + ```text Apache License Version 2.0, January 2004 @@ -5650,6 +5731,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #### NOTICE + + ```text procfs provides functions to retrieve system, kernel and process metrics from the pseudo-filesystem proc. @@ -5664,11 +5747,13 @@ SoundCloud Ltd. (http://soundcloud.com/). ### github.com/russross/blackfriday/v2 +* Version: v2.1.0 * License: BSD-2-Clause -* Module: github.com/russross/blackfriday/v2 #### LICENSE.txt + + ```text Blackfriday is distributed under the Simplified BSD License: @@ -5705,11 +5790,13 @@ Blackfriday is distributed under the Simplified BSD License: ### github.com/sirupsen/logrus +* Version: v1.10.0 * License: MIT -* Module: github.com/sirupsen/logrus #### LICENSE + + ```text The MIT License (MIT) @@ -5738,11 +5825,13 @@ THE SOFTWARE. ### github.com/spf13/pflag +* Version: v1.0.10 * License: BSD-3-Clause -* Module: github.com/spf13/pflag #### LICENSE + + ```text Copyright (c) 2012 Alex Ogier. All rights reserved. Copyright (c) 2012 The Go Authors. All rights reserved. @@ -5778,11 +5867,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### github.com/urfave/cli/v2 +* Version: v2.27.7 * License: MIT -* Module: github.com/urfave/cli/v2 #### LICENSE + + ```text MIT License @@ -5811,11 +5902,13 @@ SOFTWARE. ### github.com/x448/float16 +* Version: v0.8.4 * License: MIT -* Module: github.com/x448/float16 #### LICENSE + + ```text MIT License @@ -5845,11 +5938,13 @@ SOFTWARE. ### github.com/xrash/smetrics +* Version: v0.0.0-20240521201337-686a1a2994c1 * License: MIT -* Module: github.com/xrash/smetrics #### LICENSE + + ```text Copyright (C) 2016 Felipe da Cunha Gonçalves All Rights Reserved. @@ -5878,11 +5973,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ### go.yaml.in/yaml/v2 -* License: Apache-2.0 -* Module: go.yaml.in/yaml/v2 +* Version: v2.4.3 +* License: Apache-2.0 / MIT #### LICENSE + + ```text Apache License Version 2.0, January 2004 @@ -6088,8 +6185,49 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ``` +#### LICENSE.libyaml + + + +```text +The following files were ported to Go from C files of libyaml, and thus +are still covered by their original copyright and license: + + apic.go + emitterc.go + parserc.go + readerc.go + scannerc.go + writerc.go + yamlh.go + yamlprivateh.go + +Copyright (c) 2006 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. + +``` + #### NOTICE + + ```text Copyright 2011-2016 Canonical Ltd. @@ -6110,11 +6248,13 @@ limitations under the License. ### go.yaml.in/yaml/v3 -* License: MIT -* Module: go.yaml.in/yaml/v3 +* Version: v3.0.4 +* License: Apache-2.0 / MIT #### LICENSE + + ```text This project is covered by two different licenses: MIT and Apache. @@ -6171,6 +6311,8 @@ limitations under the License. #### NOTICE + + ```text Copyright 2011-2016 Canonical Ltd. @@ -6191,11 +6333,13 @@ limitations under the License. ### golang.org/x/mod/semver +* Version: v0.40.0 * License: BSD-3-Clause -* Module: golang.org/x/mod #### LICENSE + + ```text Copyright 2009 The Go Authors. @@ -6227,14 +6371,46 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ``` +#### PATENTS + + + +```text +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. + +``` + ### golang.org/x/net +* Version: v0.56.0 * License: BSD-3-Clause -* Module: golang.org/x/net #### LICENSE + + ```text Copyright 2009 The Go Authors. @@ -6266,14 +6442,46 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ``` +#### PATENTS + + + +```text +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. + +``` + ### golang.org/x/oauth2 +* Version: v0.36.0 * License: BSD-3-Clause -* Module: golang.org/x/oauth2 #### LICENSE + + ```text Copyright 2009 The Go Authors. @@ -6308,11 +6516,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### golang.org/x/sys/unix +* Version: v0.47.0 * License: BSD-3-Clause -* Module: golang.org/x/sys #### LICENSE + + ```text Copyright 2009 The Go Authors. @@ -6344,14 +6554,46 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ``` +#### PATENTS + + + +```text +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. + +``` + ### golang.org/x/term +* Version: v0.44.0 * License: BSD-3-Clause -* Module: golang.org/x/term #### LICENSE + + ```text Copyright 2009 The Go Authors. @@ -6383,14 +6625,46 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ``` +#### PATENTS + + + +```text +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. + +``` + ### golang.org/x/text +* Version: v0.41.0 * License: BSD-3-Clause -* Module: golang.org/x/text #### LICENSE + + ```text Copyright 2009 The Go Authors. @@ -6422,14 +6696,46 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ``` +#### PATENTS + + + +```text +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. + +``` + ### golang.org/x/time/rate +* Version: v0.15.0 * License: BSD-3-Clause -* Module: golang.org/x/time #### LICENSE + + ```text Copyright 2009 The Go Authors. @@ -6461,14 +6767,46 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ``` +#### PATENTS + + + +```text +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. + +``` + ### google.golang.org/genproto/googleapis/rpc/status +* Version: v0.0.0-20260526163538-3dc84a4a5aaa * License: Apache-2.0 -* Module: google.golang.org/genproto/googleapis/rpc #### LICENSE + + ```text Apache License @@ -6678,11 +7016,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### google.golang.org/grpc +* Version: v1.83.1 * License: Apache-2.0 -* Module: google.golang.org/grpc + +#### AUTHORS + + + +```text +Google Inc. + +``` #### LICENSE + + ```text Apache License @@ -6891,6 +7240,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #### NOTICE.txt + + ```text Copyright 2014 gRPC authors. @@ -6911,11 +7262,13 @@ limitations under the License. ### google.golang.org/protobuf +* Version: v1.36.12-0.20260120151049-f2248ac996af * License: BSD-3-Clause -* Module: google.golang.org/protobuf #### LICENSE + + ```text Copyright (c) 2018 The Go Authors. All rights reserved. @@ -6947,14 +7300,46 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ``` +#### PATENTS + + + +```text +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. + +``` + ### gopkg.in/evanphx/json-patch.v4 +* Version: v4.13.0 * License: BSD-3-Clause -* Module: gopkg.in/evanphx/json-patch.v4 #### LICENSE + + ```text Copyright (c) 2014, Evan Phoenix All rights reserved. @@ -6987,11 +7372,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### gopkg.in/inf.v0 +* Version: v0.9.1 * License: BSD-3-Clause -* Module: gopkg.in/inf.v0 #### LICENSE + + ```text Copyright (c) 2012 Péter Surányi. Portions Copyright (c) 2009 The Go Authors. All rights reserved. @@ -7027,11 +7414,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### gopkg.in/yaml.v3 -* License: MIT -* Module: gopkg.in/yaml.v3 +* Version: v3.0.1 +* License: Apache-2.0 / MIT #### LICENSE + + ```text This project is covered by two different licenses: MIT and Apache. @@ -7088,6 +7477,8 @@ limitations under the License. #### NOTICE + + ```text Copyright 2011-2016 Canonical Ltd. @@ -7108,11 +7499,13 @@ limitations under the License. ### k8s.io/api +* Version: v0.36.3 * License: Apache-2.0 -* Module: k8s.io/api #### LICENSE + + ```text Apache License @@ -7322,11 +7715,13 @@ limitations under the License. ### k8s.io/apimachinery/pkg +* Version: v0.36.3 * License: Apache-2.0 -* Module: k8s.io/apimachinery #### LICENSE + + ```text Apache License @@ -7536,11 +7931,13 @@ limitations under the License. ### k8s.io/apimachinery/third_party/forked/golang +* Version: v0.36.3 * License: BSD-3-Clause -* Module: k8s.io/apimachinery #### LICENSE + + ```text Copyright (c) 2009 The Go Authors. All rights reserved. @@ -7572,14 +7969,46 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ``` +#### PATENTS + + + +```text +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. + +``` + ### k8s.io/client-go +* Version: v0.36.3 * License: Apache-2.0 -* Module: k8s.io/client-go #### LICENSE + + ```text Apache License @@ -7789,11 +8218,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### k8s.io/klog/v2 +* Version: v2.140.0 * License: Apache-2.0 -* Module: k8s.io/klog/v2 #### LICENSE + + ```text Apache License Version 2.0, January 2004 @@ -7992,11 +8423,13 @@ third-party archives. ### k8s.io/kube-openapi/pkg +* Version: v0.0.0-20260317180543-43fb72c5454a * License: Apache-2.0 -* Module: k8s.io/kube-openapi #### LICENSE + + ```text Apache License @@ -8206,11 +8639,24 @@ third-party archives. ### k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json +* Version: v0.0.0-20260317180543-43fb72c5454a * License: BSD-3-Clause -* Module: k8s.io/kube-openapi + +#### AUTHORS + + + +```text +# This source code refers to The Go Authors for copyright purposes. +# The master list of authors is in the main Go distribution, +# visible at https://tip.golang.org/AUTHORS. + +``` #### LICENSE + + ```text Copyright (c) 2020 The Go Authors. All rights reserved. @@ -8245,11 +8691,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### k8s.io/kube-openapi/pkg/validation/spec +* Version: v0.0.0-20260317180543-43fb72c5454a * License: Apache-2.0 -* Module: k8s.io/kube-openapi #### LICENSE + + ```text Apache License @@ -8459,11 +8907,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### k8s.io/kubelet/pkg/apis/deviceplugin/v1beta1 +* Version: v0.36.3 * License: Apache-2.0 -* Module: k8s.io/kubelet #### LICENSE + + ```text Apache License @@ -8673,11 +9123,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### k8s.io/mount-utils +* Version: v0.36.3 * License: Apache-2.0 -* Module: k8s.io/mount-utils #### LICENSE + + ```text Apache License Version 2.0, January 2004 @@ -8886,11 +9338,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### k8s.io/utils +* Version: v0.0.0-20260210185600-b8788abfbbc2 * License: Apache-2.0 -* Module: k8s.io/utils #### LICENSE + + ```text Apache License @@ -9100,11 +9554,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### k8s.io/utils/internal/third_party/forked/golang/net +* Version: v0.0.0-20260210185600-b8788abfbbc2 * License: BSD-3-Clause -* Module: k8s.io/utils #### LICENSE + + ```text Copyright (c) 2012 The Go Authors. All rights reserved. @@ -9136,14 +9592,46 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ``` +#### PATENTS + + + +```text +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google 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, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. + +``` + ### sigs.k8s.io/json +* Version: v0.0.0-20250730193827-2d320260d730 * License: Apache-2.0 / BSD-3-Clause -* Module: sigs.k8s.io/json #### LICENSE + + ```text Files other than internal/golang/* licensed under: @@ -9389,11 +9877,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### sigs.k8s.io/node-feature-discovery/api/generated +* Version: v0.19.0 * License: Apache-2.0 -* Module: sigs.k8s.io/node-feature-discovery #### LICENSE + + ```text Apache License Version 2.0, January 2004 @@ -9577,11 +10067,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### sigs.k8s.io/node-feature-discovery/api/nfd/v1alpha1 +* Version: v0.19.0 * License: Apache-2.0 -* Module: sigs.k8s.io/node-feature-discovery/api/nfd #### LICENSE + + ```text Apache License Version 2.0, January 2004 @@ -9765,11 +10257,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ### sigs.k8s.io/randfill +* Version: v1.0.0 * License: Apache-2.0 -* Module: sigs.k8s.io/randfill #### LICENSE + + ```text Apache License Version 2.0, January 2004 @@ -9978,6 +10472,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #### NOTICE + + ```text 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 @@ -10009,11 +10505,13 @@ Submitted on behalf of a third-party: @disconnect3d (Disconnect3d) ### sigs.k8s.io/structured-merge-diff/v6 +* Version: v6.4.0 * License: Apache-2.0 -* Module: sigs.k8s.io/structured-merge-diff/v6 #### LICENSE + + ```text Apache License Version 2.0, January 2004 @@ -10222,11 +10720,13 @@ Submitted on behalf of a third-party: @disconnect3d (Disconnect3d) ### sigs.k8s.io/yaml +* Version: v1.6.0 * License: Apache-2.0 / BSD-3-Clause / MIT -* Module: sigs.k8s.io/yaml #### LICENSE + + ```text The MIT License (MIT) @@ -10540,11 +11040,13 @@ Apache license: ### tags.cncf.io/container-device-interface +* Version: v1.1.0 * License: Apache-2.0 -* Module: tags.cncf.io/container-device-interface #### LICENSE + + ```text Apache License Version 2.0, January 2004 @@ -10753,11 +11255,13 @@ Apache license: ### tags.cncf.io/container-device-interface/specs-go +* Version: v1.1.0 * License: Apache-2.0 -* Module: tags.cncf.io/container-device-interface/specs-go #### LICENSE + + ```text Apache License Version 2.0, January 2004 diff --git a/hack/generate-third-party-notices.sh b/hack/generate-third-party-notices.sh index f746384d9..d18102b32 100755 --- a/hack/generate-third-party-notices.sh +++ b/hack/generate-third-party-notices.sh @@ -52,14 +52,14 @@ log() { # Licenses that are themselves Markdown close a fixed ``` fence early and invert # every block after it, so open with one backtick more than the file's longest run. fence_for() { - local file="$1" longest width + local file="$1" longest_backtick_run fence_width # -a: a license holding a NUL byte would otherwise print "Binary file ... # matches" instead of the matches, on stdout or stderr depending on the grep. - longest=$(LC_ALL=C grep -oaE '`+' "${file}" 2>/dev/null \ - | awk '{ if (length($0) > m) m = length($0) } END { print m+0 }') - width=$(( longest + 1 )) - (( width < 3 )) && width=3 - printf '%*s' "${width}" '' | tr ' ' '`' + longest_backtick_run=$(LC_ALL=C grep -oaE '`+' "${file}" 2>/dev/null \ + | awk '{ if (length($0) > m) m = length($0) } END { print m+0 }' || true) + fence_width=$(( longest_backtick_run + 1 )) + (( fence_width < 3 )) && fence_width=3 + printf '%*s' "${fence_width}" '' | tr ' ' '`' } check_prerequisites() { @@ -77,9 +77,10 @@ check_prerequisites() { "not rebuilt: delete it and re-run." fi - local f - for f in "${MULTI_ARCH_MK}" "${MODULES_TXT}"; do - [[ -f "${f}" ]] || die "${f} not found — run 'make third-party-notices' from the repo root." + local required_file + for required_file in "${MULTI_ARCH_MK}" "${MODULES_TXT}" "${LICENSE_OVERRIDES}"; do + [[ -f "${required_file}" ]] \ + || die "${required_file} not found — run 'make third-party-notices' from the repo root." done LOCAL_MODULE=$(go list -m 2>/dev/null || true) @@ -118,10 +119,10 @@ prepare_workspace() { mkdir -p "${LICENSES_DIR}" # Explicit templates: macOS mktemp ignores TMPDIR without one. - local t="${TMPDIR:-/tmp}/k8s-device-plugin-notices" - SAVE_ROOT="$(mktemp -d "${t}.XXXXXX")" - COMBINED_CSV="$(mktemp "${t}-csv.XXXXXX")" - INDEX_FILE="$(mktemp "${t}-idx.XXXXXX")" + local workspace_template="${TMPDIR:-/tmp}/k8s-device-plugin-notices" + SAVE_ROOT="$(mktemp -d "${workspace_template}.XXXXXX")" + COMBINED_CSV="$(mktemp "${workspace_template}-csv.XXXXXX")" + INDEX_FILE="$(mktemp "${workspace_template}-idx.XXXXXX")" # Composed beside its destination, not under TMPDIR, so the last step is a # same-filesystem rename(2) rather than a copy-then-unlink. @@ -186,10 +187,10 @@ collapse_index() { ' } -# Rows carry module names from modules.txt rather than a URL: in vendor mode -# go-licenses reports a URL into this repo at HEAD, which stops describing -# released content once main moves. Versions are intentionally omitted because -# the notices identify dependencies and their licenses, not an exact build. +# Rows carry the module path and version from modules.txt rather than a URL: +# in vendor mode go-licenses reports a URL into this repo at HEAD, which stops +# describing released content once main moves and names our copy, not +# upstream. The verified upstream location comes from hack/license-urls.tsv. # Longest prefix wins: a license may sit below the module root. annotate_modules() { awk -v modfile="${MODULES_TXT}" ' @@ -209,9 +210,11 @@ annotate_modules() { } mods[++m] = f[2] disp[f[2]] = f[r] + ver[f[2]] = f[r + 1] } else { mods[++m] = f[2] disp[f[2]] = f[2] + ver[f[2]] = f[3] } } close(modfile) @@ -227,7 +230,7 @@ annotate_modules() { mp = mods[i] if (($1 == mp || index($1, mp "/") == 1) && length(mp) > length(best)) best = mp } - print $0, (best == "" ? "unknown" : disp[best]) + print $0, (best == "" ? "unknown" : disp[best]), (best == "" ? "unknown" : ver[best]) } ' } @@ -246,6 +249,11 @@ build_indexes() { "Re-run 'make vendor' first; if it persists, fix annotate_modules in hack/generate-third-party-notices.sh." fi + if cut -d, -f5 "${INDEX_FILE}" | LC_ALL=C grep -qx 'unknown'; then + die "some packages could not be matched to a version in ${MODULES_TXT}." \ + "Re-run 'make vendor' first; if it persists, fix annotate_modules in hack/generate-third-party-notices.sh." + fi + # go-licenses reports a license it cannot classify as "Unknown" and exits 0. # Anchored both sides: licenses are joined with " / ", and an identifier # merely starting with "Unknown" must not match. An empty field would also @@ -254,57 +262,166 @@ build_indexes() { die "go-licenses could not identify a license for some dependencies." \ "Check the entries reported as Unknown before committing the file." fi + + check_override_coverage "${INDEX_FILE}" +} + +# A dropped dependency would otherwise leave its row in LICENSE_OVERRIDES +# silently asserting a license for a package no longer shipped. +check_override_coverage() { + local index="$1" override_package + while IFS=$'\t' read -r override_package _ _; do + case "${override_package}" in + ''|'#'*) continue ;; + esac + LC_ALL=C cut -d, -f1 "${index}" | LC_ALL=C grep -qFx "${override_package}" \ + || die "${LICENSE_OVERRIDES} has a row for ${override_package}, which is not in the generated index." \ + "Remove that row from ${LICENSE_OVERRIDES} — the dependency was likely dropped." + done < "${LICENSE_OVERRIDES}" } -# License-bearing files, sorted. Filter by name: for restricted licenses -# 'go-licenses save' copies the whole module source, which does not belong here. +# Filter by name: for restricted licenses 'go-licenses save' copies the whole +# module source, which does not belong here. license_files_for() { - local dir="$1" f - [[ -d "${dir}" ]] || return 0 - while IFS= read -r -d '' f; do - if printf '%s' "$(basename "${f}")" \ + local search_dir="$1" license_file file_basename + [[ -d "${search_dir}" ]] || return 0 + while IFS= read -r -d '' license_file; do + file_basename="$(basename "${license_file}")" + # Exclude source files: the name pattern below also matches source + # files that merely start with a license-shaped header, e.g. + # k8s.io/kube-openapi/pkg/validation/spec/license.go, a Go file + # beginning "// Copyright 2015 go-swagger maintainers". + case "${file_basename}" in + *.go|*.c|*.h|*.s|*.py|*.sh|*.java|*.ts|*.js) continue ;; + esac + if printf '%s' "${file_basename}" \ | LC_ALL=C grep -qiE '^(licen[cs]e|notice|copying|copyright|authors|patents)([-._].*)?$'; then - printf '%s\n' "${f}" + printf '%s\n' "${license_file}" fi - done < <(find "${dir}" -maxdepth 1 -type f -print0 2>/dev/null | LC_ALL=C sort -z) + done < <(find "${search_dir}" -maxdepth 1 -type f -print0 2>/dev/null | LC_ALL=C sort -z) } -emit_index_table() { - local index="$1" pkg _ license module - printf '| Package | License | Dependency |\n' - printf '|---------|---------|------------|\n' +LICENSE_URLS="${LICENSE_URLS:-hack/license-urls.tsv}" +LICENSE_OVERRIDES="${LICENSE_OVERRIDES:-hack/license-overrides.tsv}" +VENDOR_DIR="${VENDOR_DIR:-vendor}" + +# Separate from check_prerequisites: hack/verify-license-urls.sh reuses the +# collection stages to discover which license files the document will link, and +# it is the command that produces this map, so it must run without it. +require_url_map() { + [[ -f "${LICENSE_URLS}" ]] \ + || die "${LICENSE_URLS} not found." \ + "Run 'make third-party-notices-urls' (needs network) and commit the result." +} - while IFS=, read -r pkg _ license module; do - [[ -z "${pkg}" ]] && continue +# A single license file can bundle more than one license, which go-licenses +# reports as whichever one it scores highest; LICENSE_OVERRIDES corrects the +# identifier by hand without touching the license text, which is unaffected. +license_identifier_for() { + local package="$1" default_identifier="$2" override_identifier + override_identifier="$(LC_ALL=C awk -F'\t' -v pkg="${package}" \ + '$1 == pkg { print $2; exit }' "${LICENSE_OVERRIDES}")" + printf '%s' "${override_identifier:-${default_identifier}}" +} + +# The first enclosing directory holding a license file wins, which is how +# go-licenses attributes them. +license_dir_within_module() { + local module="$2" dir="$1" relative + while :; do + if [[ -n "$(license_files_for "${VENDOR_DIR}/${dir}")" ]]; then + relative="${dir#"${module}"}" + printf '%s' "${relative#/}" + return 0 + fi + [[ "${dir}" == "${module}" ]] && return 1 + [[ "${dir}" != */* ]] && return 1 + dir="${dir%/*}" + done +} + +location_for() { + local url + url="$(LC_ALL=C awk -F'\t' -v m="$1" -v v="$2" -v p="$3" \ + '$1 == m && $2 == v && $3 == p { print $4; found = 1; exit } + END { exit !found }' "${LICENSE_URLS}")" || return 1 + [[ -n "${url}" ]] || return 1 + printf '%s' "${url}" +} + +# Mirrors how the License column joins identifiers. +location_cell() { + local package="$1" module="$2" version="$3" + local relative_license_dir license_file_name license_path url cell="" license_file governing_dir + relative_license_dir="$(license_dir_within_module "${package}" "${module}")" \ + || die "no license file found for ${package} under ${VENDOR_DIR}/${module}." \ + "Run 'make vendor' and re-run." + governing_dir="${VENDOR_DIR}/${module}${relative_license_dir:+/${relative_license_dir}}" + while IFS= read -r license_file; do + [[ -z "${license_file}" ]] && continue + license_file_name="$(basename "${license_file}")" + license_path="${relative_license_dir:+${relative_license_dir}/}${license_file_name}" + url="$(location_for "${module}" "${version}" "${license_path}")" \ + || die "${LICENSE_URLS} has no verified URL for ${module}@${version} ${license_path}." \ + "Run 'make third-party-notices-urls' (needs network) and commit the result." + cell="${cell:+${cell} / }[${license_file_name}](${url})" + done < <(license_files_for "${governing_dir}") + [[ -n "${cell}" ]] || die "no license file for ${package} under ${governing_dir}." \ + "Run 'make vendor' and re-run." + printf '%s' "${cell}" +} + +emit_index_table() { + local index="$1" package _ license module version location license_identifier + printf '| Package | Version | License | Location |\n' + printf '|---------|---------|---------|----------|\n' + + while IFS=, read -r package _ license module version; do + [[ -z "${package}" ]] && continue + location="$(location_cell "${package}" "${module}" "${version}")" + license_identifier="$(license_identifier_for "${package}" "${license:-Unknown}")" # shellcheck disable=SC2016 # backticks are literal markdown here. - printf '| `%s` | %s | `%s` |\n' "${pkg}" "${license:-Unknown}" "${module:-unknown}" + printf '| `%s` | %s | %s | %s |\n' \ + "${package}" "${version:-unknown}" \ + "${license_identifier}" "${location}" done < "${index}" } emit_sections() { - local index="$1" root="$2" - local pkg _ license module files lf fence + local index="$1" + local package _ license module version files license_file fence relative_license_dir license_file_name url governing_dir license_identifier - while IFS=, read -r pkg _ license module; do - [[ -z "${pkg}" ]] && continue + while IFS=, read -r package _ license module version; do + [[ -z "${package}" ]] && continue - printf '### %s\n\n' "${pkg}" - printf '* License: %s\n' "${license:-Unknown}" - printf '* Module: %s\n\n' "${module:-unknown}" + license_identifier="$(license_identifier_for "${package}" "${license:-Unknown}")" + printf '### %s\n\n' "${package}" + printf '* Version: %s\n' "${version:-unknown}" + printf '* License: %s\n\n' "${license_identifier}" + + relative_license_dir="$(license_dir_within_module "${package}" "${module}")" \ + || die "no license file found for ${package} under ${VENDOR_DIR}/${module}." \ + "Run 'make vendor' and re-run." + governing_dir="${VENDOR_DIR}/${module}${relative_license_dir:+/${relative_license_dir}}" files=() - while IFS= read -r lf; do - [[ -n "${lf}" ]] && files+=("${lf}") - done < <(license_files_for "${root}/${pkg}") + while IFS= read -r license_file; do + [[ -n "${license_file}" ]] && files+=("${license_file}") + done < <(license_files_for "${governing_dir}") if (( ${#files[@]} == 0 )); then printf 'License text unavailable. See upstream source for the full license.\n' else - for lf in "${files[@]}"; do - fence="$(fence_for "${lf}")" - printf '#### %s\n\n' "$(basename "${lf}")" + for license_file in "${files[@]}"; do + license_file_name="$(basename "${license_file}")" + url="$(location_for "${module}" "${version}" "${relative_license_dir:+${relative_license_dir}/}${license_file_name}")" \ + || die "${LICENSE_URLS} has no verified URL for ${module}@${version} ${relative_license_dir:+${relative_license_dir}/}${license_file_name}." \ + "Run 'make third-party-notices-urls' (needs network) and commit the result." + fence="$(fence_for "${license_file}")" + printf '#### %s\n\n' "${license_file_name}" + printf '<%s>\n\n' "${url}" printf '%stext\n' "${fence}" - cat "${lf}" + cat "${license_file}" echo printf '%s\n' "${fence}" echo @@ -315,6 +432,7 @@ emit_sections() { } compose_document() { + require_url_map log "Composing ${OUTPUT}..." { cat <<'EOF' @@ -331,6 +449,13 @@ platform. The `nvidia-device-plugin`, `gpu-feature-discovery`, `k8s-device-plugin` image. Go standard library packages are excluded; they are covered by the license of the Go distribution itself. +Each dependency is listed with the version redistributed and a link to the +license file in that version's upstream source. Every link was verified by +fetching it and comparing its contents against the copy vendored here, so each +one resolves to the same license text reproduced below. Modules that no command +under `cmd/` links are not listed; those are vendored only for this module's own +tests and build tooling. + The `k8s-device-plugin` image uses `nvcr.io/nvidia/distroless/go` as a base image. All of the OSS packages and source included in this image can be found at . A statically @@ -346,7 +471,7 @@ EOF ## License Texts EOF - emit_sections "${INDEX_FILE}" "${LICENSES_DIR}" + emit_sections "${INDEX_FILE}" } > "${OUT_TMP}" # mktemp creates 0600, so fix the mode before the rename. mv, not cp: the # rename is atomic, so a failed run leaves the previous document intact. @@ -368,4 +493,8 @@ main() { log "Wrote ${OUTPUT} (${count} Go packages)" } -main "$@" +# Sourced by the tests and by hack/verify-license-urls.sh, which reuse these +# functions without the side effects of a full run. +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main "$@" +fi diff --git a/hack/generate-third-party-notices_test.sh b/hack/generate-third-party-notices_test.sh new file mode 100755 index 000000000..972e34233 --- /dev/null +++ b/hack/generate-third-party-notices_test.sh @@ -0,0 +1,194 @@ +#!/usr/bin/env bash +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT 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 -uo pipefail + +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=hack/test-helpers.sh disable=SC1091 +source "${HERE}/test-helpers.sh" + +# If the guard ever regresses, sourcing must not overwrite the committed +# notices file. OUTPUT is honoured by compose_document. +OUTPUT="$(mktemp)" +export OUTPUT + +# shellcheck source=hack/generate-third-party-notices.sh disable=SC1091 +source "${HERE}/generate-third-party-notices.sh" + +# If the guard is missing, sourcing runs the generator and exits before here. +assert_eq "sourced" "sourced" "sourcing the generator does not execute main" + +# Environment-independent: proves the guard is present rather than relying on +# main failing fast, which it only does on a host without go-licenses. +assert_eq "1" \ + "$(LC_ALL=C grep -c 'BASH_SOURCE\[0\]' "${HERE}/generate-third-party-notices.sh")" \ + "the generator guards main against running on source" + +fixture="$(mktemp)" +trap 'rm -f "${fixture}"' EXIT +printf 'plain text, no backticks\n' > "${fixture}" +assert_eq '```' "$(fence_for "${fixture}")" "fence_for: minimum width is three" +printf 'a ```` b\n' > "${fixture}" +assert_eq '`````' "$(fence_for "${fixture}")" "fence_for: one wider than the longest run" + +modules_fixture="$(mktemp)" +cat > "${modules_fixture}" <<'MODULES' +# k8s.io/apimachinery v0.36.3 +## explicit +# go.yaml.in/yaml/v2 v2.4.3 +MODULES + +index_input="$(mktemp)" +cat > "${index_input}" <<'ROWS' +k8s.io/apimachinery,ignored,Apache-2.0 +k8s.io/apimachinery/third_party/forked/golang,ignored,BSD-3-Clause +go.yaml.in/yaml/v2,ignored,Apache-2.0 +ROWS + +assert_eq "k8s.io/apimachinery/third_party/forked/golang,ignored,BSD-3-Clause,k8s.io/apimachinery,v0.36.3" \ + "$(MODULES_TXT="${modules_fixture}" annotate_modules < "${index_input}" | sed -n 2p)" \ + "annotate_modules appends module and version" +assert_eq "go.yaml.in/yaml/v2,ignored,Apache-2.0,go.yaml.in/yaml/v2,v2.4.3" \ + "$(MODULES_TXT="${modules_fixture}" annotate_modules < "${index_input}" | sed -n 3p)" \ + "annotate_modules resolves a root module" + +urls_fixture="$(mktemp)" +{ + printf 'k8s.io/apimachinery\tv0.36.3\tLICENSE\thttps://example.invalid/apimachinery\n' + printf 'k8s.io/apimachinery\tv0.36.3\tthird_party/forked/golang/LICENSE\thttps://example.invalid/forked-golang\n' + printf 'go.yaml.in/yaml/v2\tv2.4.3\tLICENSE\thttps://example.invalid/yaml-v2\n' + printf 'go.yaml.in/yaml/v2\tv2.4.3\tLICENSE.libyaml\thttps://example.invalid/yaml-v2-libyaml\n' +} > "${urls_fixture}" + +# No rows: exercises license_identifier_for's not-found path so the fixtures +# below that do not care about overrides are unaffected by them, without +# depending on the LICENSE_OVERRIDES default resolving from the test's cwd. +empty_overrides_fixture="$(mktemp)" +printf '# no overrides\n' > "${empty_overrides_fixture}" + +assert_eq "https://example.invalid/forked-golang" \ + "$(LICENSE_URLS="${urls_fixture}" location_for \ + k8s.io/apimachinery v0.36.3 third_party/forked/golang/LICENSE)" \ + "location_for finds a nested license path" +# $1 is expanded by the child bash -c, not here. +# shellcheck disable=SC2016 +assert_fails "location_for fails closed on a miss" \ + env LICENSE_URLS="${urls_fixture}" bash -c \ + 'source "$1"; location_for github.com/nope v1.0.0 LICENSE' \ + _ "${HERE}/generate-third-party-notices.sh" + +license_files_fixture="$(mktemp -d)" +touch "${license_files_fixture}/LICENSE" "${license_files_fixture}/LICENSE.md" "${license_files_fixture}/license.go" +assert_eq "$(printf '%s/LICENSE\n%s/LICENSE.md' "${license_files_fixture}" "${license_files_fixture}")" \ + "$(license_files_for "${license_files_fixture}")" \ + "license_files_for excludes a Go source file even when its name matches" +rm -rf "${license_files_fixture}" + +vendor_fixture="$(mktemp -d)" +mkdir -p "${vendor_fixture}/k8s.io/apimachinery/third_party/forked/golang" +mkdir -p "${vendor_fixture}/go.yaml.in/yaml/v2" +touch "${vendor_fixture}/k8s.io/apimachinery/LICENSE" +touch "${vendor_fixture}/k8s.io/apimachinery/third_party/forked/golang/LICENSE" +touch "${vendor_fixture}/go.yaml.in/yaml/v2/LICENSE" +touch "${vendor_fixture}/go.yaml.in/yaml/v2/LICENSE.libyaml" +assert_eq "third_party/forked/golang" \ + "$(VENDOR_DIR="${vendor_fixture}" license_dir_within_module \ + k8s.io/apimachinery/third_party/forked/golang k8s.io/apimachinery)" \ + "license_dir_within_module finds the nearest enclosing license" +assert_eq "" \ + "$(VENDOR_DIR="${vendor_fixture}" license_dir_within_module \ + k8s.io/apimachinery k8s.io/apimachinery)" \ + "license_dir_within_module is empty at the module root" +# $1 is expanded by the child bash -c, not here. +# shellcheck disable=SC2016 +assert_fails "license_dir_within_module fails when no license exists" \ + env VENDOR_DIR="${vendor_fixture}" bash -c \ + 'source "$1"; license_dir_within_module github.com/absent/mod github.com/absent/mod' \ + _ "${HERE}/generate-third-party-notices.sh" + +render="$(mktemp -d)" +mkdir -p "${render}/cache/k8s.io/apimachinery/third_party/forked/golang" +printf 'BSD text\n' > "${render}/cache/k8s.io/apimachinery/third_party/forked/golang/LICENSE" +cat > "${render}/index.csv" <<'IDX' +k8s.io/apimachinery/third_party/forked/golang,ignored,BSD-3-Clause,k8s.io/apimachinery,v0.36.3 +go.yaml.in/yaml/v2,ignored,Apache-2.0,go.yaml.in/yaml/v2,v2.4.3 +IDX + +assert_eq '| Package | Version | License | Location |' \ + "$(LICENSE_URLS="${urls_fixture}" VENDOR_DIR="${vendor_fixture}" LICENSES_DIR="${render}/cache" \ + LICENSE_OVERRIDES="${empty_overrides_fixture}" emit_index_table "${render}/index.csv" | sed -n 1p)" \ + "index header has four columns" +# Expected literal Markdown, not shell expansion. +# shellcheck disable=SC2016 +assert_eq '| `k8s.io/apimachinery/third_party/forked/golang` | v0.36.3 | BSD-3-Clause | [LICENSE](https://example.invalid/forked-golang) |' \ + "$(LICENSE_URLS="${urls_fixture}" VENDOR_DIR="${vendor_fixture}" LICENSES_DIR="${render}/cache" \ + LICENSE_OVERRIDES="${empty_overrides_fixture}" emit_index_table "${render}/index.csv" | sed -n 3p)" \ + "index row labels the link by filename" + +# Regression: a package whose module/version pair has no entry in the URL map +# must abort the whole table, not render with a blank Location cell. +mismatch_index="${render}/mismatch-index.csv" +cat > "${mismatch_index}" <<'IDX' +k8s.io/apimachinery/third_party/forked/golang,ignored,BSD-3-Clause,k8s.io/apimachinery,v9.9.9 +IDX +# $1/$2 are expanded by the child bash -c, not here. +# shellcheck disable=SC2016 +assert_fails "emit_index_table fails closed when the URL map has no entry for a row" \ + env LICENSE_URLS="${urls_fixture}" VENDOR_DIR="${vendor_fixture}" LICENSES_DIR="${render}/cache" \ + LICENSE_OVERRIDES="${empty_overrides_fixture}" \ + bash -c 'source "$1"; emit_index_table "$2"' _ "${HERE}/generate-third-party-notices.sh" "${mismatch_index}" + +section="$(LICENSE_URLS="${urls_fixture}" VENDOR_DIR="${vendor_fixture}" LICENSES_DIR="${render}/cache" \ + LICENSE_OVERRIDES="${empty_overrides_fixture}" emit_sections "${render}/index.csv" "${render}/cache")" +assert_eq "* Version: v0.36.3" "$(printf '%s' "${section}" | sed -n 3p)" "section names the version" +assert_eq "* License: BSD-3-Clause" "$(printf '%s' "${section}" | sed -n 4p)" "section names the license" +assert_eq "0" "$(printf '%s' "${section}" | LC_ALL=C grep -c '^\* Module: ')" "section no longer names the module" +assert_eq "" \ + "$(printf '%s' "${section}" | LC_ALL=C grep -m1 '^ "${overrides_fixture}" <<'OVERRIDES' +# package license reason +go.yaml.in/yaml/v2 Apache-2.0 / MIT test fixture +gopkg.in/yaml.v3 Apache-2.0 / MIT test fixture +OVERRIDES + +assert_eq "Apache-2.0 / MIT" \ + "$(LICENSE_OVERRIDES="${overrides_fixture}" license_identifier_for go.yaml.in/yaml/v2 Apache-2.0)" \ + "license_identifier_for returns the override for a package that has one" +assert_eq "BSD-3-Clause" \ + "$(LICENSE_OVERRIDES="${overrides_fixture}" license_identifier_for k8s.io/apimachinery BSD-3-Clause)" \ + "license_identifier_for returns the passed-in default for a package without an override" + +# Expected literal Markdown, not shell expansion. +# shellcheck disable=SC2016 +assert_eq '| `go.yaml.in/yaml/v2` | v2.4.3 | Apache-2.0 / MIT | [LICENSE](https://example.invalid/yaml-v2) / [LICENSE.libyaml](https://example.invalid/yaml-v2-libyaml) |' \ + "$(LICENSE_URLS="${urls_fixture}" VENDOR_DIR="${vendor_fixture}" LICENSES_DIR="${render}/cache" \ + LICENSE_OVERRIDES="${overrides_fixture}" emit_index_table "${render}/index.csv" | sed -n 4p)" \ + "emit_index_table renders the overridden identifier in the License column" + +stale_overrides="$(mktemp)" +printf 'github.com/absent/package\tApache-2.0 / MIT\ttest fixture\n' > "${stale_overrides}" +# $1/$2 are expanded by the child bash -c, not here. +# shellcheck disable=SC2016 +assert_fails "check_override_coverage fails when an override names a package absent from the index" \ + env LICENSE_OVERRIDES="${stale_overrides}" bash -c \ + 'source "$1"; check_override_coverage "$2"' _ "${HERE}/generate-third-party-notices.sh" "${render}/index.csv" + +rm -rf "${vendor_fixture}" "${render}" +rm -f "${modules_fixture}" "${index_input}" "${urls_fixture}" "${empty_overrides_fixture}" "${overrides_fixture}" "${stale_overrides}" + +finish diff --git a/hack/license-overrides.tsv b/hack/license-overrides.tsv new file mode 100644 index 000000000..ef79a3e7a --- /dev/null +++ b/hack/license-overrides.tsv @@ -0,0 +1,16 @@ +# Curated license identifiers for packages whose license file bundles more +# than one license as a single document. go-licenses classifies such a file +# as whichever license it scores highest and reports only that one, so the +# reported identifier understates the terms even though the license text +# reproduced in THIRD_PARTY_NOTICES.md already carries every license in full. +# +# Add a row here only when you have read the vendored license file yourself +# and confirmed by eye which licenses it actually contains — do not derive +# an entry by grepping license text for phrases, which cannot reliably tell +# similar licenses apart (e.g. BSD-2-Clause vs BSD-3-Clause) and risks adding +# a wrong claim to a legal document. +# +# package license reason +go.yaml.in/yaml/v2 Apache-2.0 / MIT ships LICENSE (Apache-2.0) and LICENSE.libyaml (MIT) as two files; go-licenses reports only the Apache-2.0 LICENSE +go.yaml.in/yaml/v3 Apache-2.0 / MIT single LICENSE file has a full-text MIT section plus a short-form Apache-2.0 grant; go-licenses reports only MIT +gopkg.in/yaml.v3 Apache-2.0 / MIT single LICENSE file has a full-text MIT section plus a short-form Apache-2.0 grant; go-licenses reports only MIT diff --git a/hack/license-url-lib.sh b/hack/license-url-lib.sh new file mode 100755 index 000000000..d30f50ab8 --- /dev/null +++ b/hack/license-url-lib.sh @@ -0,0 +1,156 @@ +#!/usr/bin/env bash +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Pure string transforms shared by the resolvers and the notices generator. +# No network and (except base64_decode, which reads stdin) no I/O, so every +# rule here is testable offline. + +# The module proxy case-encodes an uppercase letter as '!' plus its lowercase +# form: github.com/NVIDIA -> github.com/!n!v!i!d!i!a. This MUST NOT be done with +# sed: 's/\([A-Z]\)/!\l\1/g' yields '!lN!lV...' on BSD sed, which the proxy +# rejects as an invalid escaped module path. +proxy_escape() { + printf '%s' "$1" | awk '{ + n = split($0, chars, "") + out = "" + for (i = 1; i <= n; i++) { + c = chars[i] + out = out (c ~ /[A-Z]/ ? "!" tolower(c) : c) + } + print out + }' +} + +strip_major_suffix() { + if [[ "$1" =~ ^(.*)/v[0-9]+$ ]]; then + printf '%s' "${BASH_REMATCH[1]}" + else + printf '%s' "$1" + fi +} + +normalize_version() { + printf '%s' "${1%+incompatible}" +} + +# A pseudo-version ends in <14-digit UTC timestamp>-<12-hex commit>. That +# trailing hash is the only ref such a module has; there is no tag. +# Pre-release versions have an optional 0. prefix before the timestamp. +pseudo_version_hash() { + if [[ "$1" =~ -[0-9.]*[0-9]{14}-([0-9a-f]{12})$ ]]; then + printf '%s' "${BASH_REMATCH[1]}" + fi +} + +normalize_repo_url() { + local url="${1%/}" + printf '%s' "${url%.git}" +} + +github_repo_from_path() { + local module rest org repo + module="$(strip_major_suffix "$1")" + case "${module}" in github.com/*) ;; *) return 0 ;; esac + rest="${module#github.com/}" + org="${rest%%/*}" + rest="${rest#*/}" + repo="${rest%%/*}" + [[ -n "${org}" && -n "${repo}" && "${org}" != "${module}" ]] || return 0 + printf 'https://github.com/%s/%s' "${org}" "${repo}" +} + +# The module's directory inside a github repository, derived from the path +# alone. GitHub serves no go-import meta, so when the proxy has no Origin this +# is the only source of the submodule tag prefix; without it a module such as +# github.com/Mellanox/maintenance-operator/api loses its 'api/' tag and no +# candidate URL can match. +github_subdir_from_path() { + local module rest + module="$(strip_major_suffix "$1")" + case "${module}" in github.com/*) ;; *) return 0 ;; esac + rest="${module#github.com/}" + [[ "${rest}" == */* ]] || return 0 + rest="${rest#*/}" # drop org + [[ "${rest}" == */* ]] || return 0 + printf '%s' "${rest#*/}" # drop repo +} + +# gopkg.in publishes a go-import pointing at itself, which serves no blobs. +# Its documented convention maps onto GitHub. +gopkg_in_repo() { + local rest user pkg + case "$1" in gopkg.in/*) ;; *) return 0 ;; esac + rest="${1#gopkg.in/}" + if [[ "${rest}" == */* ]]; then + user="${rest%%/*}" + pkg="${rest#*/}" + printf 'https://github.com/%s/%s' "${user}" "${pkg%.v*}" + else + pkg="${rest%.v*}" + printf 'https://github.com/go-%s/%s' "${pkg}" "${pkg}" + fi +} + +derived_subdir() { + local module prefix + module="$(strip_major_suffix "$1")" + prefix="$(strip_major_suffix "$2")" + [[ "${module}" == "${prefix}" ]] && return 0 + [[ "${module}" == "${prefix}/"* ]] || return 0 + printf '%s' "${module#"${prefix}/"}" +} + +# Gerrit serves blobs under /+//, not /blob//. +blob_url() { + local repo="$1" ref="$2" path="$3" + case "${repo}" in + https://go.googlesource.com/*) printf '%s/+/%s/%s' "${repo}" "${ref}" "${path}" ;; + *) printf '%s/blob/%s/%s' "${repo}" "${ref}" "${path}" ;; + esac +} + +raw_url_for() { + local blob="$1" rest owner repo + case "${blob}" in + https://github.com/*) + rest="${blob#https://github.com/}" + owner="${rest%%/*}"; rest="${rest#*/}" + repo="${rest%%/*}"; rest="${rest#*/}" + rest="${rest#blob/}" + printf 'https://raw.githubusercontent.com/%s/%s/%s' "${owner}" "${repo}" "${rest}" + ;; + https://go.googlesource.com/*) + printf '%s?format=TEXT' "${blob}" + ;; + esac +} + +raw_is_base64() { + case "$1" in https://go.googlesource.com/*) return 0 ;; *) return 1 ;; esac +} + +# GNU coreutils spells the decode flag -d; BSD documents -D. Probe once rather +# than assuming, or every Gerrit-hosted module fails to hash on a strict BSD. +base64_decode() { + if [[ -z "${BASE64_DECODE_FLAG:-}" ]]; then + if printf '' | base64 -d >/dev/null 2>&1; then + BASE64_DECODE_FLAG="-d" + else + BASE64_DECODE_FLAG="-D" + fi + fi + base64 "${BASE64_DECODE_FLAG}" +} diff --git a/hack/license-url-lib_test.sh b/hack/license-url-lib_test.sh new file mode 100755 index 000000000..4ff7714ac --- /dev/null +++ b/hack/license-url-lib_test.sh @@ -0,0 +1,91 @@ +#!/usr/bin/env bash +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT 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 -uo pipefail +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=hack/test-helpers.sh disable=SC1091 +source "${HERE}/test-helpers.sh" +# shellcheck source=hack/license-url-lib.sh disable=SC1091 +source "${HERE}/license-url-lib.sh" + +# The bug that silently broke proxy resolution for all four uppercase modules. +assert_eq "github.com/!n!v!i!d!i!a/go-nvml" \ + "$(proxy_escape github.com/NVIDIA/go-nvml)" "proxy_escape lowercases with a bang" +assert_eq "github.com/!n!v!i!d!i!a/nvidia-container-toolkit" \ + "$(proxy_escape github.com/NVIDIA/nvidia-container-toolkit)" \ + "proxy_escape leaves an identically spelled lowercase segment alone" +assert_eq "k8s.io/api" "$(proxy_escape k8s.io/api)" "proxy_escape leaves lowercase alone" + +assert_eq "github.com/urfave/cli" \ + "$(strip_major_suffix github.com/urfave/cli/v2)" "strip /v2" +assert_eq "go.yaml.in/yaml" \ + "$(strip_major_suffix go.yaml.in/yaml/v3)" "strip /v3 from a vanity path" +assert_eq "gopkg.in/inf.v0" \ + "$(strip_major_suffix gopkg.in/inf.v0)" "gopkg.in .vN is not a /vN suffix" + +assert_eq "v2.0.1" "$(normalize_version 'v2.0.1+incompatible')" "strip +incompatible" +assert_eq "43fb72c5454a" \ + "$(pseudo_version_hash v0.0.0-20260317180543-43fb72c5454a)" "pseudo-version hash" +assert_eq "d8f796af33cc" \ + "$(pseudo_version_hash v1.1.2-0.20180830191138-d8f796af33cc)" "pre-release pseudo-version" +assert_eq "" "$(pseudo_version_hash v1.10.0)" "a tagged version has no hash" + +assert_eq "https://github.com/sirupsen/logrus" \ + "$(github_repo_from_path github.com/sirupsen/logrus)" "github root module" +assert_eq "https://github.com/moby/sys" \ + "$(github_repo_from_path github.com/moby/sys/capability)" "github submodule" +assert_eq "" "$(github_repo_from_path k8s.io/api)" "non-github yields empty" + +# Without this the github fallback loses the submodule tag prefix entirely. +assert_eq "capability" \ + "$(github_subdir_from_path github.com/moby/sys/capability)" "github subdir" +assert_eq "internal/spew" \ + "$(github_subdir_from_path github.com/stretchr/testify/internal/spew)" \ + "multi-segment github subdir" +assert_eq "" "$(github_subdir_from_path github.com/urfave/cli/v2)" "/vN is not a subdir" +assert_eq "" "$(github_subdir_from_path github.com/sirupsen/logrus)" "root module has no subdir" + +assert_eq "https://github.com/go-inf/inf" "$(gopkg_in_repo gopkg.in/inf.v0)" "gopkg.in single segment" +assert_eq "https://github.com/go-yaml/yaml" "$(gopkg_in_repo gopkg.in/yaml.v3)" "gopkg.in yaml" +assert_eq "https://github.com/evanphx/json-patch" \ + "$(gopkg_in_repo gopkg.in/evanphx/json-patch.v4)" "gopkg.in user/pkg" +assert_eq "" "$(gopkg_in_repo github.com/foo/bar)" "non-gopkg.in yields empty" + +assert_eq "https://github.com/cyphar/go-pathrs" \ + "$(normalize_repo_url 'https://github.com/cyphar/go-pathrs.git')" "strip .git" +assert_eq "https://github.com/foo/bar" \ + "$(normalize_repo_url 'https://github.com/foo/bar/')" "strip trailing slash" + +assert_eq "api/nfd" \ + "$(derived_subdir sigs.k8s.io/node-feature-discovery/api/nfd sigs.k8s.io/node-feature-discovery)" \ + "subdir from prefix" +assert_eq "" "$(derived_subdir github.com/sirupsen/logrus github.com/sirupsen/logrus)" "root module" + +assert_eq "https://github.com/sirupsen/logrus/blob/v1.10.0/LICENSE" \ + "$(blob_url https://github.com/sirupsen/logrus v1.10.0 LICENSE)" "github blob template" +assert_eq "https://go.googlesource.com/net/+/refs/tags/v0.56.0/LICENSE" \ + "$(blob_url https://go.googlesource.com/net refs/tags/v0.56.0 LICENSE)" "gerrit blob template" + +assert_eq "https://raw.githubusercontent.com/stretchr/testify/v1.12.0/internal/spew/LICENSE" \ + "$(raw_url_for https://github.com/stretchr/testify/blob/v1.12.0/internal/spew/LICENSE)" \ + "github raw URL" +assert_eq "https://go.googlesource.com/net/+/refs/tags/v0.56.0/LICENSE?format=TEXT" \ + "$(raw_url_for https://go.googlesource.com/net/+/refs/tags/v0.56.0/LICENSE)" "gerrit raw URL" +assert_fails "github raw is not base64" raw_is_base64 https://github.com/a/b/blob/v1/LICENSE + +assert_eq "hello" "$(printf 'aGVsbG8=' | base64_decode)" "base64_decode works on this host" + +finish diff --git a/hack/license-urls.tsv b/hack/license-urls.tsv new file mode 100644 index 000000000..3d7dfc78c --- /dev/null +++ b/hack/license-urls.tsv @@ -0,0 +1,101 @@ +# Verified upstream URL for every license file the notices document links. +# Generated by hack/verify-license-urls.sh. Each URL was fetched and its +# sha256 matched against the vendored copy, so no entry is a dead or wrong link. +# Covers the shipped set only: build- and test-only dependencies are excluded. +# module version license-path url +github.com/NVIDIA/go-gpuallocator v0.6.0 LICENSE https://github.com/NVIDIA/go-gpuallocator/blob/v0.6.0/LICENSE +github.com/NVIDIA/go-nvlib v0.12.0 LICENSE https://github.com/NVIDIA/go-nvlib/blob/v0.12.0/LICENSE +github.com/NVIDIA/go-nvlib v0.12.0 NOTICE https://github.com/NVIDIA/go-nvlib/blob/v0.12.0/NOTICE +github.com/NVIDIA/go-nvml v0.13.3-1 LICENSE https://github.com/NVIDIA/go-nvml/blob/v0.13.3-1/LICENSE +github.com/NVIDIA/nvidia-container-toolkit v1.20.0 LICENSE https://github.com/NVIDIA/nvidia-container-toolkit/blob/v1.20.0/LICENSE +github.com/cpuguy83/go-md2man/v2 v2.0.7 LICENSE.md https://github.com/cpuguy83/go-md2man/blob/v2.0.7/LICENSE.md +github.com/cyphar/filepath-securejoin v0.7.0 COPYING.md https://github.com/cyphar/filepath-securejoin/blob/v0.7.0/COPYING.md +github.com/cyphar/filepath-securejoin v0.7.0 LICENSE.BSD https://github.com/cyphar/filepath-securejoin/blob/v0.7.0/LICENSE.BSD +github.com/cyphar/filepath-securejoin v0.7.0 LICENSE.MPL-2.0 https://github.com/cyphar/filepath-securejoin/blob/v0.7.0/LICENSE.MPL-2.0 +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc LICENSE https://github.com/davecgh/go-spew/blob/d8f796af33cc/LICENSE +github.com/emicklei/go-restful/v3 v3.13.0 LICENSE https://github.com/emicklei/go-restful/blob/v3.13.0/LICENSE +github.com/fsnotify/fsnotify v1.10.1 LICENSE https://github.com/fsnotify/fsnotify/blob/v1.10.1/LICENSE +github.com/fxamacker/cbor/v2 v2.9.0 LICENSE https://github.com/fxamacker/cbor/blob/v2.9.0/LICENSE +github.com/go-logr/logr v1.4.3 LICENSE https://github.com/go-logr/logr/blob/v1.4.3/LICENSE +github.com/go-openapi/jsonpointer v0.21.0 LICENSE https://github.com/go-openapi/jsonpointer/blob/v0.21.0/LICENSE +github.com/go-openapi/jsonreference v0.20.4 LICENSE https://github.com/go-openapi/jsonreference/blob/v0.20.4/LICENSE +github.com/go-openapi/swag v0.23.0 LICENSE https://github.com/go-openapi/swag/blob/v0.23.0/LICENSE +github.com/google/gnostic-models v0.7.0 LICENSE https://github.com/google/gnostic-models/blob/v0.7.0/LICENSE +github.com/google/renameio v1.0.1 LICENSE https://github.com/google/renameio/blob/v1.0.1/LICENSE +github.com/google/uuid v1.6.0 LICENSE https://github.com/google/uuid/blob/v1.6.0/LICENSE +github.com/josharian/intern v1.0.0 license.md https://github.com/josharian/intern/blob/v1.0.0/license.md +github.com/json-iterator/go v1.1.12 LICENSE https://github.com/json-iterator/go/blob/v1.1.12/LICENSE +github.com/mailru/easyjson v0.7.7 LICENSE https://github.com/mailru/easyjson/blob/v0.7.7/LICENSE +github.com/moby/sys/capability v0.4.0 LICENSE https://github.com/moby/sys/blob/capability/v0.4.0/capability/LICENSE +github.com/moby/sys/devices v0.1.0 LICENSE https://github.com/moby/sys/blob/devices/v0.1.0/LICENSE +github.com/moby/sys/mountinfo v0.7.2 LICENSE https://github.com/moby/sys/blob/mountinfo/v0.7.2/LICENSE +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd LICENSE https://github.com/modern-go/concurrent/blob/bacd9c7ef1dd/LICENSE +github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee LICENSE https://github.com/modern-go/reflect2/blob/35a7c28c31ee/LICENSE +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 LICENSE https://github.com/munnerz/goautoneg/blob/a7dc8b61c822/LICENSE +github.com/opencontainers/cgroups v0.0.7 LICENSE https://github.com/opencontainers/cgroups/blob/v0.0.7/LICENSE +github.com/opencontainers/runc v1.5.0 LICENSE https://github.com/opencontainers/runc/blob/v1.5.0/LICENSE +github.com/opencontainers/runc v1.5.0 NOTICE https://github.com/opencontainers/runc/blob/v1.5.0/NOTICE +github.com/opencontainers/runtime-spec v1.3.0 LICENSE https://github.com/opencontainers/runtime-spec/blob/v1.3.0/LICENSE +github.com/opencontainers/runtime-tools v0.9.1-0.20251114084447-edf4cb3d2116 LICENSE https://github.com/opencontainers/runtime-tools/blob/edf4cb3d2116/LICENSE +github.com/opencontainers/selinux v1.15.1 LICENSE https://github.com/opencontainers/selinux/blob/v1.15.1/LICENSE +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 LICENSE https://github.com/pmezard/go-difflib/blob/5d4384ee4fb2/LICENSE +github.com/prometheus/procfs v0.21.1 LICENSE https://github.com/prometheus/procfs/blob/v0.21.1/LICENSE +github.com/prometheus/procfs v0.21.1 NOTICE https://github.com/prometheus/procfs/blob/v0.21.1/NOTICE +github.com/russross/blackfriday/v2 v2.1.0 LICENSE.txt https://github.com/russross/blackfriday/blob/v2.1.0/LICENSE.txt +github.com/sirupsen/logrus v1.10.0 LICENSE https://github.com/sirupsen/logrus/blob/v1.10.0/LICENSE +github.com/spf13/pflag v1.0.10 LICENSE https://github.com/spf13/pflag/blob/v1.0.10/LICENSE +github.com/urfave/cli/v2 v2.27.7 LICENSE https://github.com/urfave/cli/blob/v2.27.7/LICENSE +github.com/x448/float16 v0.8.4 LICENSE https://github.com/x448/float16/blob/v0.8.4/LICENSE +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 LICENSE https://github.com/xrash/smetrics/blob/686a1a2994c1/LICENSE +go.yaml.in/yaml/v2 v2.4.3 LICENSE https://github.com/yaml/go-yaml/blob/v2.4.3/LICENSE +go.yaml.in/yaml/v2 v2.4.3 LICENSE.libyaml https://github.com/yaml/go-yaml/blob/v2.4.3/LICENSE.libyaml +go.yaml.in/yaml/v2 v2.4.3 NOTICE https://github.com/yaml/go-yaml/blob/v2.4.3/NOTICE +go.yaml.in/yaml/v3 v3.0.4 LICENSE https://github.com/yaml/go-yaml/blob/v3.0.4/LICENSE +go.yaml.in/yaml/v3 v3.0.4 NOTICE https://github.com/yaml/go-yaml/blob/v3.0.4/NOTICE +golang.org/x/mod v0.40.0 LICENSE https://go.googlesource.com/mod/+/refs/tags/v0.40.0/LICENSE +golang.org/x/mod v0.40.0 PATENTS https://go.googlesource.com/mod/+/refs/tags/v0.40.0/PATENTS +golang.org/x/net v0.56.0 LICENSE https://go.googlesource.com/net/+/refs/tags/v0.56.0/LICENSE +golang.org/x/net v0.56.0 PATENTS https://go.googlesource.com/net/+/refs/tags/v0.56.0/PATENTS +golang.org/x/oauth2 v0.36.0 LICENSE https://go.googlesource.com/oauth2/+/refs/tags/v0.36.0/LICENSE +golang.org/x/sys v0.47.0 LICENSE https://go.googlesource.com/sys/+/refs/tags/v0.47.0/LICENSE +golang.org/x/sys v0.47.0 PATENTS https://go.googlesource.com/sys/+/refs/tags/v0.47.0/PATENTS +golang.org/x/term v0.44.0 LICENSE https://go.googlesource.com/term/+/refs/tags/v0.44.0/LICENSE +golang.org/x/term v0.44.0 PATENTS https://go.googlesource.com/term/+/refs/tags/v0.44.0/PATENTS +golang.org/x/text v0.41.0 LICENSE https://go.googlesource.com/text/+/refs/tags/v0.41.0/LICENSE +golang.org/x/text v0.41.0 PATENTS https://go.googlesource.com/text/+/refs/tags/v0.41.0/PATENTS +golang.org/x/time v0.15.0 LICENSE https://go.googlesource.com/time/+/refs/tags/v0.15.0/LICENSE +golang.org/x/time v0.15.0 PATENTS https://go.googlesource.com/time/+/refs/tags/v0.15.0/PATENTS +google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa LICENSE https://github.com/googleapis/go-genproto/blob/3dc84a4a5aaa/LICENSE +google.golang.org/grpc v1.83.1 AUTHORS https://github.com/grpc/grpc-go/blob/v1.83.1/AUTHORS +google.golang.org/grpc v1.83.1 LICENSE https://github.com/grpc/grpc-go/blob/v1.83.1/LICENSE +google.golang.org/grpc v1.83.1 NOTICE.txt https://github.com/grpc/grpc-go/blob/v1.83.1/NOTICE.txt +google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af LICENSE https://go.googlesource.com/protobuf/+/f2248ac996af/LICENSE +google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af PATENTS https://go.googlesource.com/protobuf/+/f2248ac996af/PATENTS +gopkg.in/evanphx/json-patch.v4 v4.13.0 LICENSE https://github.com/evanphx/json-patch/blob/v4.13.0/LICENSE +gopkg.in/inf.v0 v0.9.1 LICENSE https://github.com/go-inf/inf/blob/v0.9.1/LICENSE +gopkg.in/yaml.v3 v3.0.1 LICENSE https://github.com/go-yaml/yaml/blob/v3.0.1/LICENSE +gopkg.in/yaml.v3 v3.0.1 NOTICE https://github.com/go-yaml/yaml/blob/v3.0.1/NOTICE +k8s.io/api v0.36.3 LICENSE https://github.com/kubernetes/api/blob/v0.36.3/LICENSE +k8s.io/apimachinery v0.36.3 LICENSE https://github.com/kubernetes/apimachinery/blob/v0.36.3/LICENSE +k8s.io/apimachinery v0.36.3 third_party/forked/golang/LICENSE https://github.com/kubernetes/apimachinery/blob/v0.36.3/third_party/forked/golang/LICENSE +k8s.io/apimachinery v0.36.3 third_party/forked/golang/PATENTS https://github.com/kubernetes/apimachinery/blob/v0.36.3/third_party/forked/golang/PATENTS +k8s.io/client-go v0.36.3 LICENSE https://github.com/kubernetes/client-go/blob/v0.36.3/LICENSE +k8s.io/klog/v2 v2.140.0 LICENSE https://github.com/kubernetes/klog/blob/v2.140.0/LICENSE +k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a LICENSE https://github.com/kubernetes/kube-openapi/blob/43fb72c5454a/LICENSE +k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a pkg/internal/third_party/go-json-experiment/json/AUTHORS https://github.com/kubernetes/kube-openapi/blob/43fb72c5454a/pkg/internal/third_party/go-json-experiment/json/AUTHORS +k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a pkg/internal/third_party/go-json-experiment/json/LICENSE https://github.com/kubernetes/kube-openapi/blob/43fb72c5454a/pkg/internal/third_party/go-json-experiment/json/LICENSE +k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a pkg/validation/spec/LICENSE https://github.com/kubernetes/kube-openapi/blob/43fb72c5454a/pkg/validation/spec/LICENSE +k8s.io/kubelet v0.36.3 LICENSE https://github.com/kubernetes/kubelet/blob/v0.36.3/LICENSE +k8s.io/mount-utils v0.36.3 LICENSE https://github.com/kubernetes/mount-utils/blob/v0.36.3/LICENSE +k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 LICENSE https://github.com/kubernetes/utils/blob/b8788abfbbc2/LICENSE +k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 internal/third_party/forked/golang/LICENSE https://github.com/kubernetes/utils/blob/b8788abfbbc2/internal/third_party/forked/golang/LICENSE +k8s.io/utils v0.0.0-20260210185600-b8788abfbbc2 internal/third_party/forked/golang/PATENTS https://github.com/kubernetes/utils/blob/b8788abfbbc2/internal/third_party/forked/golang/PATENTS +sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 LICENSE https://github.com/kubernetes-sigs/json/blob/2d320260d730/LICENSE +sigs.k8s.io/node-feature-discovery v0.19.0 LICENSE https://github.com/kubernetes-sigs/node-feature-discovery/blob/v0.19.0/LICENSE +sigs.k8s.io/node-feature-discovery/api/nfd v0.19.0 LICENSE https://github.com/kubernetes-sigs/node-feature-discovery/blob/api/nfd/v0.19.0/LICENSE +sigs.k8s.io/randfill v1.0.0 LICENSE https://github.com/kubernetes-sigs/randfill/blob/v1.0.0/LICENSE +sigs.k8s.io/randfill v1.0.0 NOTICE https://github.com/kubernetes-sigs/randfill/blob/v1.0.0/NOTICE +sigs.k8s.io/structured-merge-diff/v6 v6.4.0 LICENSE https://github.com/kubernetes-sigs/structured-merge-diff/blob/v6.4.0/LICENSE +sigs.k8s.io/yaml v1.6.0 LICENSE https://github.com/kubernetes-sigs/yaml/blob/v1.6.0/LICENSE +tags.cncf.io/container-device-interface v1.1.0 LICENSE https://github.com/cncf-tags/container-device-interface/blob/v1.1.0/LICENSE +tags.cncf.io/container-device-interface/specs-go v1.1.0 LICENSE https://github.com/cncf-tags/container-device-interface/blob/specs-go/v1.1.0/LICENSE diff --git a/hack/module-repos.tsv b/hack/module-repos.tsv new file mode 100644 index 000000000..e83550b9d --- /dev/null +++ b/hack/module-repos.tsv @@ -0,0 +1,76 @@ +# Upstream repository for each vendored module. +# Generated by hack/resolve-module-repos.sh from the module proxy Origin, +# the go-import meta tag, and the github.com path shape. Not hand-edited. +# module repo-url subdir +cyphar.com/go-pathrs https://github.com/cyphar/libpathrs go-pathrs +github.com/NVIDIA/go-gpuallocator https://github.com/NVIDIA/go-gpuallocator +github.com/NVIDIA/go-nvlib https://github.com/NVIDIA/go-nvlib +github.com/NVIDIA/go-nvml https://github.com/NVIDIA/go-nvml +github.com/NVIDIA/nvidia-container-toolkit https://github.com/NVIDIA/nvidia-container-toolkit +github.com/cpuguy83/go-md2man/v2 https://github.com/cpuguy83/go-md2man +github.com/cyphar/filepath-securejoin https://github.com/cyphar/filepath-securejoin +github.com/davecgh/go-spew https://github.com/davecgh/go-spew +github.com/emicklei/go-restful/v3 https://github.com/emicklei/go-restful +github.com/fsnotify/fsnotify https://github.com/fsnotify/fsnotify +github.com/fxamacker/cbor/v2 https://github.com/fxamacker/cbor +github.com/go-logr/logr https://github.com/go-logr/logr +github.com/go-openapi/jsonpointer https://github.com/go-openapi/jsonpointer +github.com/go-openapi/jsonreference https://github.com/go-openapi/jsonreference +github.com/go-openapi/swag https://github.com/go-openapi/swag +github.com/google/gnostic-models https://github.com/google/gnostic-models +github.com/google/renameio https://github.com/google/renameio +github.com/google/uuid https://github.com/google/uuid +github.com/josharian/intern https://github.com/josharian/intern +github.com/json-iterator/go https://github.com/json-iterator/go +github.com/mailru/easyjson https://github.com/mailru/easyjson +github.com/moby/sys/capability https://github.com/moby/sys capability +github.com/moby/sys/devices https://github.com/moby/sys devices +github.com/moby/sys/mountinfo https://github.com/moby/sys mountinfo +github.com/modern-go/concurrent https://github.com/modern-go/concurrent +github.com/modern-go/reflect2 https://github.com/modern-go/reflect2 +github.com/munnerz/goautoneg https://github.com/munnerz/goautoneg +github.com/opencontainers/cgroups https://github.com/opencontainers/cgroups +github.com/opencontainers/runc https://github.com/opencontainers/runc +github.com/opencontainers/runtime-spec https://github.com/opencontainers/runtime-spec +github.com/opencontainers/runtime-tools https://github.com/opencontainers/runtime-tools +github.com/opencontainers/selinux https://github.com/opencontainers/selinux +github.com/pmezard/go-difflib https://github.com/pmezard/go-difflib +github.com/prometheus/procfs https://github.com/prometheus/procfs +github.com/russross/blackfriday/v2 https://github.com/russross/blackfriday +github.com/sirupsen/logrus https://github.com/sirupsen/logrus +github.com/spf13/pflag https://github.com/spf13/pflag +github.com/stretchr/testify https://github.com/stretchr/testify +github.com/urfave/cli/v2 https://github.com/urfave/cli +github.com/x448/float16 https://github.com/x448/float16 +github.com/xrash/smetrics https://github.com/xrash/smetrics +go.yaml.in/yaml/v2 https://github.com/yaml/go-yaml +go.yaml.in/yaml/v3 https://github.com/yaml/go-yaml +golang.org/x/mod https://go.googlesource.com/mod +golang.org/x/net https://go.googlesource.com/net +golang.org/x/oauth2 https://go.googlesource.com/oauth2 +golang.org/x/sys https://go.googlesource.com/sys +golang.org/x/term https://go.googlesource.com/term +golang.org/x/text https://go.googlesource.com/text +golang.org/x/time https://go.googlesource.com/time +google.golang.org/genproto/googleapis/rpc https://github.com/googleapis/go-genproto googleapis/rpc +google.golang.org/grpc https://github.com/grpc/grpc-go +google.golang.org/protobuf https://go.googlesource.com/protobuf +gopkg.in/evanphx/json-patch.v4 https://github.com/evanphx/json-patch +gopkg.in/inf.v0 https://github.com/go-inf/inf +gopkg.in/yaml.v3 https://github.com/go-yaml/yaml +k8s.io/api https://github.com/kubernetes/api +k8s.io/apimachinery https://github.com/kubernetes/apimachinery +k8s.io/client-go https://github.com/kubernetes/client-go +k8s.io/klog/v2 https://github.com/kubernetes/klog +k8s.io/kube-openapi https://github.com/kubernetes/kube-openapi +k8s.io/kubelet https://github.com/kubernetes/kubelet +k8s.io/mount-utils https://github.com/kubernetes/mount-utils +k8s.io/utils https://github.com/kubernetes/utils +sigs.k8s.io/json https://github.com/kubernetes-sigs/json +sigs.k8s.io/node-feature-discovery https://github.com/kubernetes-sigs/node-feature-discovery +sigs.k8s.io/node-feature-discovery/api/nfd https://github.com/kubernetes-sigs/node-feature-discovery api/nfd +sigs.k8s.io/randfill https://github.com/kubernetes-sigs/randfill +sigs.k8s.io/structured-merge-diff/v6 https://github.com/kubernetes-sigs/structured-merge-diff +sigs.k8s.io/yaml https://github.com/kubernetes-sigs/yaml +tags.cncf.io/container-device-interface https://github.com/cncf-tags/container-device-interface +tags.cncf.io/container-device-interface/specs-go https://github.com/cncf-tags/container-device-interface specs-go diff --git a/hack/resolve-module-repos.sh b/hack/resolve-module-repos.sh new file mode 100755 index 000000000..5ac607a81 --- /dev/null +++ b/hack/resolve-module-repos.sh @@ -0,0 +1,173 @@ +#!/usr/bin/env bash +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# Resolves every module in vendor/modules.txt to its upstream repository and +# writes hack/module-repos.tsv. +# +# Needs network; run via 'make third-party-notices-repos'. Keyed by module and +# not by version: a repository normally does not move when a dependency is +# bumped, so this file survives bumps and changes only when a new module enters +# the tree. That is a convenience, not a guarantee — Task 5's content +# verification is what actually enforces correctness, and it fails loudly if a +# mapping has gone stale. + +set -euo pipefail + +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=hack/license-url-lib.sh disable=SC1091 +source "${HERE}/license-url-lib.sh" + +MODULES_TXT="${MODULES_TXT:-vendor/modules.txt}" +OUTPUT="${OUTPUT:-hack/module-repos.tsv}" +PROXY="${PROXY:-https://proxy.golang.org}" + +die() { + printf 'ERROR: %s\n' "$1" >&2 + shift + (( $# > 0 )) && printf '%s\n' "$@" >&2 + exit 1 +} +log() { printf '%s\n' "$*" >&2; } + +# Retries cover genuine network flakiness only. Absence of Origin is a real, +# permanent property of older proxy cache entries, not a transient failure. +fetch_retry() { + local url="$1" attempt body + for attempt in 1 2 3; do + body="$(curl -sfL --max-time 30 "${url}" 2>/dev/null)" || body="" + [[ -n "${body}" ]] && { printf '%s' "${body}"; return 0; } + sleep $(( attempt * 2 )) + done + return 1 +} + +origin_field() { + printf '%s' "$1" | python3 -c ' +import json, sys +try: + origin = json.load(sys.stdin).get("Origin") or {} +except Exception: + origin = {} +print(origin.get(sys.argv[1], "")) +' "$2" 2>/dev/null || printf '' +} + +# go-import content is " ". The meta tag is +# frequently split across lines, so newlines are folded before matching. +go_import_meta() { + fetch_retry "https://$1?go-get=1" 2>/dev/null \ + | tr '\n' ' ' | tr -s ' ' \ + | LC_ALL=C grep -oE 'name="go-import"[^>]*content="[^"]*"' \ + | head -1 \ + | LC_ALL=C sed -E 's/.*content="([^"]*)".*/\1/' +} + +main() { + command -v curl >/dev/null 2>&1 || die "curl is not installed." + command -v python3 >/dev/null 2>&1 || die "python3 is not installed." + [[ -f "${MODULES_TXT}" ]] \ + || die "${MODULES_TXT} not found — run 'make third-party-notices-repos' from the repo root." + + local repos_tmp_file unresolved=0 + repos_tmp_file="$(mktemp "${TMPDIR:-/tmp}/k8s-device-plugin-repos.XXXXXX")" + trap 'rm -f "${repos_tmp_file}"' EXIT + + local module version module_info_json repo import_prefix subdir go_import_meta_content converted_repo_url + local unresolved_modules="" + while read -r module version; do + [[ -z "${module}" ]] && continue + + repo=""; import_prefix=""; subdir=""; module_info_json="" + + if module_info_json="$(fetch_retry "${PROXY}/$(proxy_escape "${module}")/@v/${version}.info")"; then + repo="$(origin_field "${module_info_json}" URL)" + subdir="$(origin_field "${module_info_json}" Subdir)" + fi + + if [[ -z "${repo}" ]]; then + go_import_meta_content="$(go_import_meta "${module}")" || go_import_meta_content="" + if [[ -n "${go_import_meta_content}" ]]; then + import_prefix="$(printf '%s' "${go_import_meta_content}" | awk '{print $1}')" + repo="$(printf '%s' "${go_import_meta_content}" | awk '{print $3}')" + fi + fi + + [[ -z "${repo}" ]] && repo="$(github_repo_from_path "${module}")" + repo="$(normalize_repo_url "${repo}")" + + # gopkg.in points at itself and serves no blobs. + case "${repo}" in + https://gopkg.in/*|"") + converted_repo_url="$(gopkg_in_repo "${module}")" + [[ -n "${converted_repo_url}" ]] && repo="${converted_repo_url}" + ;; + esac + + if [[ -z "${repo}" ]]; then + log "UNRESOLVED ${module}: no repository could be determined" + unresolved=$(( unresolved + 1 )) + unresolved_modules="${unresolved_modules}${unresolved_modules:+ }${module}" + continue + fi + + # Subdir precedence: proxy Origin, then the go-import prefix, then the + # github path shape. The last matters because GitHub serves no + # go-import, so a github submodule with no Origin would otherwise lose + # its tag prefix and never verify. + if [[ -z "${subdir}" && -n "${import_prefix}" ]]; then + subdir="$(derived_subdir "${module}" "${import_prefix}")" + fi + if [[ -z "${subdir}" ]]; then + subdir="$(github_subdir_from_path "${module}")" + fi + + printf '%s\t%s\t%s\n' "${module}" "${repo}" "${subdir}" >> "${repos_tmp_file}" + done < <(LC_ALL=C grep '^# ' "${MODULES_TXT}" | awk '{print $2, $3}') + + # A warning, not a die: this resolves every module in modules.txt, including + # the ten-odd build/test-only ones out of scope for the notices document, so + # an unreachable vanity host on one of those must not block refreshing + # notices for an unrelated shipped bump. Fail-closed is still preserved — + # hack/verify-license-urls.sh dies when an IN-SCOPE module has no entry in + # this map. Do not turn this back into a die without also scoping the loop + # above to shipped modules only. + if (( unresolved > 0 )); then + log "WARNING: ${unresolved} module(s) could not be resolved to a repository: ${unresolved_modules}" + log "Re-run; if the warning persists the module's vanity host is unreachable." + fi + + { + printf '# Upstream repository for each vendored module.\n' + printf '# Generated by hack/resolve-module-repos.sh from the module proxy Origin,\n' + printf '# the go-import meta tag, and the github.com path shape. Not hand-edited.\n' + printf '# module\trepo-url\tsubdir\n' + LC_ALL=C sort "${repos_tmp_file}" + } > "${OUTPUT}" + + log "Wrote ${OUTPUT} ($(LC_ALL=C grep -vc '^#' "${OUTPUT}") modules)" + + # Exit here, not by falling off the end: the EXIT trap above references + # repos_tmp_file, a variable local to this function. If main merely + # returns, the process's implicit exit fires that trap after + # repos_tmp_file has gone out of scope, and 'set -u' turns the cleanup + # itself into an unbound-variable failure that clobbers this function's + # success with exit 1. + exit 0 +} + +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main "$@" +fi diff --git a/hack/test-helpers.sh b/hack/test-helpers.sh new file mode 100755 index 000000000..2a37e1f6a --- /dev/null +++ b/hack/test-helpers.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +TESTS_RUN=0 +TESTS_FAILED=0 + +assert_eq() { + local expected="$1" actual="$2" description="$3" + TESTS_RUN=$(( TESTS_RUN + 1 )) + if [[ "${expected}" != "${actual}" ]]; then + TESTS_FAILED=$(( TESTS_FAILED + 1 )) + printf 'FAIL: %s\n expected: [%s]\n actual: [%s]\n' \ + "${description}" "${expected}" "${actual}" >&2 + fi +} + +# Output is captured so an expected failure does not pollute the log. +assert_fails() { + local description="$1" + shift + TESTS_RUN=$(( TESTS_RUN + 1 )) + if "$@" >/dev/null 2>&1; then + TESTS_FAILED=$(( TESTS_FAILED + 1 )) + printf 'FAIL: %s\n expected non-zero exit, got 0\n' "${description}" >&2 + fi +} + +finish() { + printf '%s: %d assertions, %d failures\n' \ + "$(basename "${0}")" "${TESTS_RUN}" "${TESTS_FAILED}" >&2 + (( TESTS_FAILED == 0 )) +} diff --git a/hack/verify-license-urls.sh b/hack/verify-license-urls.sh new file mode 100755 index 000000000..0cf35962c --- /dev/null +++ b/hack/verify-license-urls.sh @@ -0,0 +1,226 @@ +#!/usr/bin/env bash +# Copyright (c) NVIDIA CORPORATION. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Resolves and verifies the upstream URL of every license file the notices +# document links, writing hack/license-urls.tsv. +# +# Needs network; run via 'make third-party-notices-urls'. A URL is written ONLY +# if the bytes it serves hash to the same sha256 as the vendored copy, so no +# entry can be a dead link or point at the wrong licence. +# +# Scope is the shipped set: this sources the notices generator and runs its +# collection stages, so it verifies exactly the packages go-licenses attributes +# to ./cmd/..., never the build- and test-only modules vendor/ also contains. + +set -euo pipefail + +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=hack/license-url-lib.sh disable=SC1091 +source "${HERE}/license-url-lib.sh" +# shellcheck source=hack/generate-third-party-notices.sh disable=SC1091 +source "${HERE}/generate-third-party-notices.sh" + +REPOS_MAP="${REPOS_MAP:-hack/module-repos.tsv}" +URLS_OUTPUT="${URLS_OUTPUT:-hack/license-urls.tsv}" +PROXY="${PROXY:-https://proxy.golang.org}" + +sha256_of_file() { + if command -v sha256sum >/dev/null 2>&1; then + sha256sum "$1" | cut -d' ' -f1 + else + shasum -a 256 "$1" | cut -d' ' -f1 + fi +} + +sha256_of_stdin() { + if command -v sha256sum >/dev/null 2>&1; then + sha256sum | cut -d' ' -f1 + else + shasum -a 256 | cut -d' ' -f1 + fi +} + +remote_sha() { + local blob="$1" raw + raw="$(raw_url_for "${blob}")" + [[ -n "${raw}" ]] || return 1 + if raw_is_base64 "${blob}"; then + curl -sfL --max-time 30 "${raw}" 2>/dev/null | base64_decode 2>/dev/null | sha256_of_stdin + else + curl -sfL --max-time 30 "${raw}" 2>/dev/null | sha256_of_stdin + fi +} + +repo_field() { + LC_ALL=C awk -F'\t' -v m="$1" -v want="$2" \ + '$1 == m { print (want == "repo" ? $2 : $3); found = 1; exit } + END { exit !found }' "${REPOS_MAP}" +} + +# Version-specific provenance. Fetched here rather than stored in the repos map, +# which is deliberately version-independent. Origin.Hash is the only pinned ref +# left when upstream deletes or rewrites a tag. +origin_ref_and_hash() { + local module="$1" version="$2" info + info="$(curl -sfL --max-time 30 \ + "${PROXY}/$(proxy_escape "${module}")/@v/${version}.info" 2>/dev/null)" || return 0 + printf '%s' "${info}" | python3 -c ' +import json, sys +try: + origin = json.load(sys.stdin).get("Origin") or {} +except Exception: + origin = {} +ref = origin.get("Ref", "") +# Only a tag pins a release. Every golang.org/x module reports +# refs/heads/master, and a branch ref would float. +print(ref[len("refs/tags/"):] if ref.startswith("refs/tags/") else "") +print(origin.get("Hash", "")) +' 2>/dev/null || printf '\n\n' +} + +main() { + command -v curl >/dev/null 2>&1 || die "curl is not installed." + command -v python3 >/dev/null 2>&1 || die "python3 is not installed." + [[ -f "${REPOS_MAP}" ]] \ + || die "${REPOS_MAP} not found — run 'make third-party-notices-repos' first." + + check_prerequisites + verify_platform_matrix + prepare_workspace + collect_licenses + build_indexes + + local verified_urls_tmp_file failures=0 + verified_urls_tmp_file="$(mktemp "${TMPDIR:-/tmp}/k8s-device-plugin-urls.XXXXXX")" + + local package _ module version repo subdir relative + local origin_tag origin_hash plain_version pseudo_version_hash_value license_file name path_in_module want_sha found_url + while IFS=, read -r package _ _ module version; do + [[ -z "${package}" ]] && continue + + repo="$(repo_field "${module}" repo)" \ + || die "${REPOS_MAP} has no entry for ${module}." \ + "Run 'make third-party-notices-repos' and commit the result." + subdir="$(repo_field "${module}" subdir)" || subdir="" + + origin_tag="$(origin_ref_and_hash "${module}" "${version}" | sed -n 1p)" + origin_hash="$(origin_ref_and_hash "${module}" "${version}" | sed -n 2p)" + + # Ref candidates, most specific first. Never a branch ref. Commit + # hashes (pseudo-version hash, Origin.Hash) are tracked apart from tag + # names: go.googlesource.com serves a tag under refs/tags/ but a raw + # commit only under its bare hash, so qualifying a hash the same way + # 404s a pseudo-versioned module such as google.golang.org/protobuf. + local tag_refs=() hash_refs=() + plain_version="$(normalize_version "${version}")" + pseudo_version_hash_value="$(pseudo_version_hash "${version}")" + [[ -n "${origin_tag}" ]] && tag_refs+=( "${origin_tag}" ) + if [[ -n "${pseudo_version_hash_value}" ]]; then + hash_refs+=( "${pseudo_version_hash_value}" ) + else + [[ -n "${subdir}" ]] && tag_refs+=( "${subdir}/${plain_version}" ) + tag_refs+=( "${plain_version}" ) + fi + [[ -n "${origin_hash}" ]] && hash_refs+=( "${origin_hash}" ) + + local refs=() tag_ref + if (( ${#tag_refs[@]} > 0 )); then + case "${repo}" in + https://go.googlesource.com/*) + for tag_ref in "${tag_refs[@]}"; do refs+=( "refs/tags/${tag_ref}" ); done + ;; + *) + refs+=( "${tag_refs[@]}" ) + ;; + esac + fi + (( ${#hash_refs[@]} > 0 )) && refs+=( "${hash_refs[@]}" ) + (( ${#refs[@]} > 0 )) || die "no ref candidates for ${module}@${version}." + + relative="$(license_dir_within_module "${package}" "${module}")" \ + || die "no license file found for ${package} under ${VENDOR_DIR}/${module}." + + local license_file_count=0 + while IFS= read -r license_file; do + [[ -z "${license_file}" ]] && continue + license_file_count=$(( license_file_count + 1 )) + name="$(basename "${license_file}")" + path_in_module="${relative:+${relative}/}${name}" + [[ -f "${VENDOR_DIR}/${module}/${path_in_module}" ]] \ + || die "${VENDOR_DIR}/${module}/${path_in_module} does not exist." + want_sha="$(sha256_of_file "${VENDOR_DIR}/${module}/${path_in_module}")" + + # Both layouts: a submodule may ship its own licence or inherit the + # repository root's. Content decides which is real. Built as an + # array rather than an unquoted ${x:+...} expansion, which would + # word-split a path containing whitespace or a glob character. + local paths=() + [[ -n "${subdir}" ]] && paths+=( "${subdir}/${path_in_module}" ) + paths+=( "${path_in_module}" ) + + found_url="" + local try_ref try_path candidate remote_sha_value + for try_ref in "${refs[@]}"; do + for try_path in "${paths[@]}"; do + candidate="$(blob_url "${repo}" "${try_ref}" "${try_path}")" + # remote_sha's own exit status must gate the match: curl + # failing (404, DNS, timeout, rate-limit) yields no bytes, + # and sha256 of no bytes is a real, fixed hash value — so + # checking only the printed string would treat a failed + # fetch as a match against any zero-byte vendored file. + if remote_sha_value="$(remote_sha "${candidate}")" && [[ "${remote_sha_value}" == "${want_sha}" ]]; then + found_url="${candidate}" + break 2 + fi + done + done + + if [[ -z "${found_url}" ]]; then + log "UNVERIFIED ${module}@${version} ${path_in_module}" + failures=$(( failures + 1 )) + continue + fi + printf '%s\t%s\t%s\t%s\n' "${module}" "${version}" "${path_in_module}" "${found_url}" >> "${verified_urls_tmp_file}" + done < <(license_files_for "${VENDOR_DIR}/${module}${relative:+/${relative}}") + + if (( license_file_count == 0 )); then + log "UNVERIFIED ${module}@${version} — no license file found for ${package}" + failures=$(( failures + 1 )) + fi + done < "${INDEX_FILE}" + + (( failures == 0 )) || die \ + "${failures} license file(s) could not be matched to a verified upstream URL." \ + "Every URL must serve bytes identical to the vendored copy; none of the" \ + "candidates did. The repository mapping may be stale — re-run" \ + "'make third-party-notices-repos' before investigating further." + + { + printf '# Verified upstream URL for every license file the notices document links.\n' + printf '# Generated by hack/verify-license-urls.sh. Each URL was fetched and its\n' + printf '# sha256 matched against the vendored copy, so no entry is a dead or wrong link.\n' + printf '# Covers the shipped set only: build- and test-only dependencies are excluded.\n' + printf '# module\tversion\tlicense-path\turl\n' + LC_ALL=C sort -u "${verified_urls_tmp_file}" + } > "${URLS_OUTPUT}" + rm -f "${verified_urls_tmp_file}" + + log "Wrote ${URLS_OUTPUT} ($(LC_ALL=C grep -vc '^#' "${URLS_OUTPUT}") verified URLs)" + exit 0 +} + +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + main "$@" +fi From b153a82e08133c83f6d60220bf54ab71c10a7a00 Mon Sep 17 00:00:00 2001 From: Abrar Shivani Date: Thu, 27 Aug 2026 12:33:31 -0700 Subject: [PATCH 2/4] Retry transient failures when verifying license URLs go.googlesource.com rate-limits the per-file loop the verifier drives, returning 503 and 429 under rapid sequential requests. remote_sha fetched each blob with a single curl, so a rate-limited response made that license file count as unverified and, because the gate is fail-closed, killed the run. Both codes were observed against golang.org/x and google.golang.org/protobuf while regenerating release notices, and both succeeded on a later attempt. The weekly link check drives the same loop, so it would have reported link rot that had not happened. The retry distinguishes a transient failure from a permanent one. curl -f collapses every failure into exit 22, so the status is read explicitly and a 404 still fails on the first request: this loops over several candidate refs and paths per file, and retrying a genuine miss would multiply the runtime of the whole run. fetch_retry moves into license-url-lib.sh as http_fetch_to_file so both resolvers share one retry and status policy. It writes to a file rather than returning the body, because command substitution strips trailing newlines, which would change the sha256 of every license file that ends in one. Successive requests to one host are also spaced, so the limiter is less likely to trip at all. Re-resolving module-repos.tsv against the live proxy after the change produces a byte-identical map, so sharing the fetcher is not a behaviour change. Signed-off-by: Abrar Shivani --- hack/license-url-lib.sh | 49 +++++++++++++++++++++-- hack/license-url-lib_test.sh | 76 ++++++++++++++++++++++++++++++++++++ hack/resolve-module-repos.sh | 22 ++++++----- hack/verify-license-urls.sh | 21 ++++++++-- 4 files changed, 153 insertions(+), 15 deletions(-) diff --git a/hack/license-url-lib.sh b/hack/license-url-lib.sh index d30f50ab8..f7c4f30aa 100755 --- a/hack/license-url-lib.sh +++ b/hack/license-url-lib.sh @@ -14,9 +14,52 @@ # limitations under the License. # -# Pure string transforms shared by the resolvers and the notices generator. -# No network and (except base64_decode, which reads stdin) no I/O, so every -# rule here is testable offline. +# Shared by the resolvers and the notices generator, in two parts. +# +# Everything below http_fetch_to_file is a pure string transform: no network +# and (except base64_decode, which reads stdin) no I/O, so every rule is +# testable offline. http_fetch_to_file itself is the one HTTP fetch both +# resolvers use, kept here so there is a single retry and status policy. + +# The single HTTP fetch for both resolvers. Writes bytes to a file rather than +# returning them: command substitution strips trailing newlines, which would +# change the sha256 of every license file that ends in one. +# +# curl -f is deliberately not used here. It reports every failure as exit 22, +# which cannot distinguish a retryable 503 from a permanent 404 -- and retrying +# a genuine miss matters, because this drives a loop over several candidate +# refs and paths per license file. +HTTP_FETCH_ATTEMPTS="${HTTP_FETCH_ATTEMPTS:-3}" + +# Successive requests to one host are what trips a rate limiter, so pause +# between them. go.googlesource.com returns 503 and 429 under the tight +# per-file loop this drives; both were observed against golang.org/x and +# google.golang.org/protobuf, and both succeeded on a later attempt. +HTTP_FETCH_THROTTLE_SECONDS="${HTTP_FETCH_THROTTLE_SECONDS:-0.2}" +HTTP_FETCH_LAST_HOST="" + +http_fetch_to_file() { + local url="$1" destination="$2" attempt status host + + host="${url#*://}" + host="${host%%/*}" + [[ "${host}" == "${HTTP_FETCH_LAST_HOST}" ]] && sleep "${HTTP_FETCH_THROTTLE_SECONDS}" + HTTP_FETCH_LAST_HOST="${host}" + + for (( attempt = 1; attempt <= HTTP_FETCH_ATTEMPTS; attempt++ )); do + status="$(curl -sL --max-time 30 --output "${destination}" \ + --write-out '%{http_code}' "${url}" 2>/dev/null)" || status="000" + case "${status}" in + 2*) return 0 ;; + # 000 is curl's own transport failure; the rest are server-side and + # temporary. Anything else (404, 401, 410) is a permanent answer. + ""|000|408|429|5*) ;; + *) return 1 ;; + esac + (( attempt < HTTP_FETCH_ATTEMPTS )) && sleep $(( attempt * 2 )) + done + return 1 +} # The module proxy case-encodes an uppercase letter as '!' plus its lowercase # form: github.com/NVIDIA -> github.com/!n!v!i!d!i!a. This MUST NOT be done with diff --git a/hack/license-url-lib_test.sh b/hack/license-url-lib_test.sh index 4ff7714ac..455d0f71c 100755 --- a/hack/license-url-lib_test.sh +++ b/hack/license-url-lib_test.sh @@ -88,4 +88,80 @@ assert_fails "github raw is not base64" raw_is_base64 https://github.com/a/b/blo assert_eq "hello" "$(printf 'aGVsbG8=' | base64_decode)" "base64_decode works on this host" +# http_fetch_to_file's retry policy. curl and sleep are shadowed by shell +# functions, so this exercises the real policy with no network and no delay. +# The distinction under test is the load-bearing one: a 503 is retried, a 404 +# is a real miss and must cost exactly one request per candidate. +# +# The stub keeps its call count and status sequence in files, not variables: +# http_fetch_to_file reads curl's output through command substitution, so the +# stub runs in a subshell and any variable it set would be discarded. +CURL_CALLS_FILE="$(mktemp)" +CURL_SEQUENCE_FILE="$(mktemp)" +FETCH_DESTINATION="$(mktemp)" +trap 'rm -f "${CURL_CALLS_FILE}" "${CURL_SEQUENCE_FILE}" "${FETCH_DESTINATION}"' EXIT + +curl() { + local destination="" + while (( $# )); do + case "$1" in + --output) destination="$2"; shift 2 ;; + *) shift ;; + esac + done + + printf '%s' "$(( $(cat "${CURL_CALLS_FILE}") + 1 ))" > "${CURL_CALLS_FILE}" + + local sequence status + sequence="$(cat "${CURL_SEQUENCE_FILE}")" + status="${sequence%% *}" + case "${sequence}" in + *' '*) printf '%s' "${sequence#* }" > "${CURL_SEQUENCE_FILE}" ;; + esac + + [[ -n "${destination}" ]] && printf 'stub-body' > "${destination}" + printf '%s' "${status}" + [[ "${status}" == "000" ]] && return 7 + return 0 +} + +sleep() { :; } + +fetch_status=0 +fetch_case() { + printf '%s' "$1" > "${CURL_SEQUENCE_FILE}" + printf '0' > "${CURL_CALLS_FILE}" + HTTP_FETCH_LAST_HOST="" + fetch_status=0 + http_fetch_to_file "https://example.test/LICENSE" "${FETCH_DESTINATION}" || fetch_status=$? +} +curl_calls() { cat "${CURL_CALLS_FILE}"; } + +fetch_case "200" +assert_eq "0" "${fetch_status}" "200 succeeds" +assert_eq "1" "$(curl_calls)" "200 costs one request" +assert_eq "stub-body" "$(cat "${FETCH_DESTINATION}")" "200 writes the body to the destination" + +fetch_case "404" +assert_eq "1" "${fetch_status}" "404 fails" +assert_eq "1" "$(curl_calls)" "404 is not retried" + +fetch_case "503 200" +assert_eq "0" "${fetch_status}" "503 then 200 succeeds" +assert_eq "2" "$(curl_calls)" "503 is retried" + +fetch_case "429 200" +assert_eq "0" "${fetch_status}" "429 then 200 succeeds" +assert_eq "2" "$(curl_calls)" "429 is retried" + +fetch_case "000 200" +assert_eq "0" "${fetch_status}" "transport failure then 200 succeeds" +assert_eq "2" "$(curl_calls)" "transport failure is retried" + +fetch_case "503 503 503" +assert_eq "1" "${fetch_status}" "persistent 503 fails" +assert_eq "3" "$(curl_calls)" "persistent 503 stops at HTTP_FETCH_ATTEMPTS" + +unset -f curl sleep + finish diff --git a/hack/resolve-module-repos.sh b/hack/resolve-module-repos.sh index 5ac607a81..f25f3fdb7 100755 --- a/hack/resolve-module-repos.sh +++ b/hack/resolve-module-repos.sh @@ -42,16 +42,20 @@ die() { } log() { printf '%s\n' "$*" >&2; } -# Retries cover genuine network flakiness only. Absence of Origin is a real, -# permanent property of older proxy cache entries, not a transient failure. +# Body-as-string wrapper over the shared fetcher. An empty body is a failure +# here but is NOT retried: absence of Origin is a real, permanent property of +# older proxy cache entries, not transient flakiness. fetch_retry() { - local url="$1" attempt body - for attempt in 1 2 3; do - body="$(curl -sfL --max-time 30 "${url}" 2>/dev/null)" || body="" - [[ -n "${body}" ]] && { printf '%s' "${body}"; return 0; } - sleep $(( attempt * 2 )) - done - return 1 + local url="$1" body_tmp_file body + body_tmp_file="$(mktemp "${TMPDIR:-/tmp}/k8s-device-plugin-fetch.XXXXXX")" + if ! http_fetch_to_file "${url}" "${body_tmp_file}"; then + rm -f "${body_tmp_file}" + return 1 + fi + body="$(cat "${body_tmp_file}")" + rm -f "${body_tmp_file}" + [[ -n "${body}" ]] || return 1 + printf '%s' "${body}" } origin_field() { diff --git a/hack/verify-license-urls.sh b/hack/verify-license-urls.sh index 0cf35962c..03326b3b3 100755 --- a/hack/verify-license-urls.sh +++ b/hack/verify-license-urls.sh @@ -52,15 +52,30 @@ sha256_of_stdin() { fi } +# Nothing may reach the hasher unless the fetch succeeded: hashing zero bytes +# yields a fixed digest that would false-match an empty vendored file. +# http_fetch_to_file retries the transient failures go.googlesource.com returns +# under this loop, and fails fast on a 404, which is a real miss. remote_sha() { - local blob="$1" raw + local blob="$1" raw blob_tmp_file sha raw="$(raw_url_for "${blob}")" [[ -n "${raw}" ]] || return 1 + + blob_tmp_file="$(mktemp "${TMPDIR:-/tmp}/k8s-device-plugin-blob.XXXXXX")" + if ! http_fetch_to_file "${raw}" "${blob_tmp_file}"; then + rm -f "${blob_tmp_file}" + return 1 + fi + if raw_is_base64 "${blob}"; then - curl -sfL --max-time 30 "${raw}" 2>/dev/null | base64_decode 2>/dev/null | sha256_of_stdin + sha="$(base64_decode < "${blob_tmp_file}" | sha256_of_stdin)" || sha="" else - curl -sfL --max-time 30 "${raw}" 2>/dev/null | sha256_of_stdin + sha="$(sha256_of_stdin < "${blob_tmp_file}")" || sha="" fi + rm -f "${blob_tmp_file}" + + [[ -n "${sha}" ]] || return 1 + printf '%s' "${sha}" } repo_field() { From 2ec915296f0c9d7acb98fcab908e699b6662f4ad Mon Sep 17 00:00:00 2001 From: Abrar Shivani Date: Thu, 27 Aug 2026 12:55:50 -0700 Subject: [PATCH 3/4] Say what the notices guarantee, not how it is produced The header described the generator's own verification process: that every link was fetched and compared "against the copy vendored here". That is build process, not attribution, and "here" only resolves for someone reading the file inside a checkout. This document is meant to be redistributable. What a reader can act on is the guarantee itself, so keep only that: the Location links to the license file at the version listed, and serves the text reproduced below. How that is enforced belongs in the tooling and the pull request, not in the notices. The sentence about modules the commands do not link was saying again what the scope paragraph already says, so the only new part, why those modules are absent, moves up into that paragraph. Signed-off-by: Abrar Shivani --- THIRD_PARTY_NOTICES.md | 15 +++++++-------- hack/generate-third-party-notices.sh | 15 +++++++-------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index 3755a3762..f7e668b22 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -9,14 +9,13 @@ the commands under `cmd/`, resolved as the union across every released image platform. The `nvidia-device-plugin`, `gpu-feature-discovery`, `mps-control-daemon` and `config-manager` commands ship in the `k8s-device-plugin` image. Go standard library packages are excluded; they are -covered by the license of the Go distribution itself. - -Each dependency is listed with the version redistributed and a link to the -license file in that version's upstream source. Every link was verified by -fetching it and comparing its contents against the copy vendored here, so each -one resolves to the same license text reproduced below. Modules that no command -under `cmd/` links are not listed; those are vendored only for this module's own -tests and build tooling. +covered by the license of the Go distribution itself. Modules used only by +this repository's tests and build tooling are not redistributed and are not +listed. + +Each dependency is listed with the version redistributed, and its Location +links to the license file in that version's upstream repository — the same +text reproduced below. The `k8s-device-plugin` image uses `nvcr.io/nvidia/distroless/go` as a base image. All of the OSS packages and source included in this image can be found at diff --git a/hack/generate-third-party-notices.sh b/hack/generate-third-party-notices.sh index d18102b32..debd0efe5 100755 --- a/hack/generate-third-party-notices.sh +++ b/hack/generate-third-party-notices.sh @@ -447,14 +447,13 @@ the commands under `cmd/`, resolved as the union across every released image platform. The `nvidia-device-plugin`, `gpu-feature-discovery`, `mps-control-daemon` and `config-manager` commands ship in the `k8s-device-plugin` image. Go standard library packages are excluded; they are -covered by the license of the Go distribution itself. - -Each dependency is listed with the version redistributed and a link to the -license file in that version's upstream source. Every link was verified by -fetching it and comparing its contents against the copy vendored here, so each -one resolves to the same license text reproduced below. Modules that no command -under `cmd/` links are not listed; those are vendored only for this module's own -tests and build tooling. +covered by the license of the Go distribution itself. Modules used only by +this repository's tests and build tooling are not redistributed and are not +listed. + +Each dependency is listed with the version redistributed, and its Location +links to the license file in that version's upstream repository — the same +text reproduced below. The `k8s-device-plugin` image uses `nvcr.io/nvidia/distroless/go` as a base image. All of the OSS packages and source included in this image can be found at From 560b1ede9c98f555797fbc2897c9425aa57cbf07 Mon Sep 17 00:00:00 2001 From: Abrar Shivani Date: Thu, 27 Aug 2026 13:02:22 -0700 Subject: [PATCH 4/4] Drop the claim that the link matches the text below it The clause restated the verification the generator already enforces, and a released notices file has nothing standing behind it: the weekly link check runs against the repository, not against a document already shipped. If upstream retags, the sentence becomes an assertion no one is checking. The license text sits directly under the link, so a reader can see the two agree without being told. What is worth saying is that the link is pinned to the listed version and points upstream rather than at our own copy, and the rest of the sentence still says that. Signed-off-by: Abrar Shivani --- THIRD_PARTY_NOTICES.md | 3 +-- hack/generate-third-party-notices.sh | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index f7e668b22..bb9c641f8 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -14,8 +14,7 @@ this repository's tests and build tooling are not redistributed and are not listed. Each dependency is listed with the version redistributed, and its Location -links to the license file in that version's upstream repository — the same -text reproduced below. +links to the license file in that version's upstream repository. The `k8s-device-plugin` image uses `nvcr.io/nvidia/distroless/go` as a base image. All of the OSS packages and source included in this image can be found at diff --git a/hack/generate-third-party-notices.sh b/hack/generate-third-party-notices.sh index debd0efe5..6591a7545 100755 --- a/hack/generate-third-party-notices.sh +++ b/hack/generate-third-party-notices.sh @@ -452,8 +452,7 @@ this repository's tests and build tooling are not redistributed and are not listed. Each dependency is listed with the version redistributed, and its Location -links to the license file in that version's upstream repository — the same -text reproduced below. +links to the license file in that version's upstream repository. The `k8s-device-plugin` image uses `nvcr.io/nvidia/distroless/go` as a base image. All of the OSS packages and source included in this image can be found at