Merge branch 'trunk' into fix-9149-set-default-remote-name
This commit is contained in:
commit
8de78e6410
929 changed files with 423 additions and 157132 deletions
23
.github/workflows/deployment.yml
vendored
23
.github/workflows/deployment.yml
vendored
|
|
@ -56,6 +56,12 @@ jobs:
|
|||
# our scripts, which rely on the specific file names generated by GoReleaser.
|
||||
version: v2.13.1
|
||||
install-only: true
|
||||
# We temporarily create a tag on HEAD to make the right version embedded
|
||||
# in the built binaries, BUT we don't push it to the remote.
|
||||
- name: Create temporary tag
|
||||
env:
|
||||
TAG_NAME: ${{ inputs.tag_name }}
|
||||
run: git tag "$TAG_NAME"
|
||||
- name: Build release binaries
|
||||
env:
|
||||
TAG_NAME: ${{ inputs.tag_name }}
|
||||
|
|
@ -111,6 +117,12 @@ jobs:
|
|||
# our scripts, which rely on the specific file names generated by GoReleaser.
|
||||
version: v2.13.1
|
||||
install-only: true
|
||||
# We temporarily create a tag on HEAD to make the right version embedded
|
||||
# in the built binaries, BUT we don't push it to the remote.
|
||||
- name: Create temporary tag
|
||||
env:
|
||||
TAG_NAME: ${{ inputs.tag_name }}
|
||||
run: git tag "$TAG_NAME"
|
||||
- name: Build release binaries
|
||||
env:
|
||||
TAG_NAME: ${{ inputs.tag_name }}
|
||||
|
|
@ -176,7 +188,7 @@ jobs:
|
|||
METADATA_PATH: ${{ runner.temp }}\acs\metadata.json
|
||||
run: |
|
||||
# Download Azure Code Signing client containing the DLL needed for signtool in script/sign
|
||||
Invoke-WebRequest -Uri https://www.nuget.org/api/v2/package/Azure.CodeSigning.Client/1.0.43 -OutFile $Env:ACS_ZIP -Verbose
|
||||
Invoke-WebRequest -Uri https://www.nuget.org/api/v2/package/Microsoft.Trusted.Signing.Client/1.0.95 -OutFile $Env:ACS_ZIP -Verbose
|
||||
Expand-Archive $Env:ACS_ZIP -Destination $Env:ACS_DIR -Force -Verbose
|
||||
|
||||
# Generate metadata file for signtool, used in signing box .exe and .msi
|
||||
|
|
@ -184,9 +196,16 @@ jobs:
|
|||
CertificateProfileName = "GitHubInc"
|
||||
CodeSigningAccountName = "GitHubInc"
|
||||
CorrelationId = $Env:CORRELATION_ID
|
||||
Endpoint = "https://wus.codesigning.azure.net/"
|
||||
Endpoint = "https://wus3.codesigning.azure.net/"
|
||||
} | ConvertTo-Json | Out-File -FilePath $Env:METADATA_PATH
|
||||
|
||||
# We temporarily create a tag on HEAD to make the right version embedded
|
||||
# in the built binaries, BUT we don't push it to the remote.
|
||||
- name: Create temporary tag
|
||||
shell: bash
|
||||
env:
|
||||
TAG_NAME: ${{ inputs.tag_name }}
|
||||
run: git tag "$TAG_NAME"
|
||||
# Azure Code Signing leverages the environment variables for secrets that complement the metadata.json
|
||||
# file generated above (AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID)
|
||||
# For more information, see https://learn.microsoft.com/en-us/dotnet/api/azure.identity.defaultazurecredential?view=azure-dotnet
|
||||
|
|
|
|||
2
.github/workflows/lint.yml
vendored
2
.github/workflows/lint.yml
vendored
|
|
@ -59,7 +59,7 @@ jobs:
|
|||
run: |
|
||||
export GOROOT=$(go env GOROOT)
|
||||
export PATH=${GOROOT}/bin:$PATH
|
||||
go install github.com/google/go-licenses@5348b744d0983d85713295ea08a20cca1654a45e # v2.0.1
|
||||
go install github.com/google/go-licenses/v2@3e084b0caf710f7bfead967567539214f598c0a2 # v2.0.1
|
||||
make licenses-check
|
||||
|
||||
# Discover vulnerabilities within Go standard libraries used to build GitHub CLI using govulncheck.
|
||||
|
|
|
|||
|
|
@ -3,14 +3,27 @@ version: "2"
|
|||
linters:
|
||||
default: none
|
||||
enable:
|
||||
- bodyclose
|
||||
- copyloopvar
|
||||
- durationcheck
|
||||
- gocritic
|
||||
- govet
|
||||
- ineffassign
|
||||
- nilerr
|
||||
- nolintlint
|
||||
- asasalint # checks for pass []any as any in variadic func(...any)
|
||||
- asciicheck # checks that your code does not contain non-ASCII identifiers
|
||||
- bidichk # checks for dangerous unicode character sequences
|
||||
- bodyclose # checks whether HTTP response body is closed successfully
|
||||
- copyloopvar # detects places where loop variables are copied (Go 1.22+)
|
||||
- durationcheck # checks for two durations multiplied together
|
||||
- exptostd # detects functions from golang.org/x/exp/ that can be replaced by std functions
|
||||
- fatcontext # detects nested contexts in loops
|
||||
- gocheckcompilerdirectives # validates go compiler directive comments (//go:)
|
||||
- gochecksumtype # checks exhaustiveness on Go "sum types"
|
||||
- gocritic # provides diagnostics that check for bugs, performance and style issues
|
||||
- gomoddirectives # manages the use of 'replace', 'retract', and 'excludes' directives in go.mod
|
||||
- goprintffuncname # checks that printf-like functions are named with f at the end
|
||||
- govet # reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
|
||||
- ineffassign # detects when assignments to existing variables are not used
|
||||
- nilerr # finds the code that returns nil even if it checks that the error is not nil
|
||||
- nolintlint # reports ill-formed or insufficient nolint directives
|
||||
- nosprintfhostport # checks for misuse of Sprintf to construct a host with port in a URL
|
||||
- reassign # checks that package variables are not reassigned
|
||||
- unused # checks for unused constants, variables, functions and types
|
||||
|
||||
# To enable later due to too many issues, and confirm we need them:
|
||||
# - gosec
|
||||
# - staticcheck
|
||||
|
|
|
|||
127
go.mod
127
go.mod
|
|
@ -44,13 +44,13 @@ require (
|
|||
github.com/rivo/tview v0.42.0
|
||||
github.com/shurcooL/githubv4 v0.0.0-20240727222349-48295856cce7
|
||||
github.com/sigstore/protobuf-specs v0.5.0
|
||||
github.com/sigstore/sigstore-go v1.1.3
|
||||
github.com/sigstore/sigstore-go v1.1.4
|
||||
github.com/spf13/cobra v1.10.2
|
||||
github.com/spf13/pflag v1.0.10
|
||||
github.com/stretchr/testify v1.11.1
|
||||
github.com/theupdateframework/go-tuf/v2 v2.3.0
|
||||
github.com/vmihailenco/msgpack/v5 v5.4.1
|
||||
github.com/yuin/goldmark v1.7.13
|
||||
github.com/yuin/goldmark v1.7.16
|
||||
github.com/zalando/go-keyring v0.2.6
|
||||
golang.org/x/crypto v0.46.0
|
||||
golang.org/x/sync v0.19.0
|
||||
|
|
@ -64,21 +64,7 @@ require (
|
|||
|
||||
require (
|
||||
al.essio.dev/pkg/shellescape v1.6.0 // indirect
|
||||
cel.dev/expr v0.24.0 // indirect
|
||||
cloud.google.com/go v0.121.6 // indirect
|
||||
cloud.google.com/go/auth v0.16.5 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.9.0 // indirect
|
||||
cloud.google.com/go/iam v1.5.2 // indirect
|
||||
cloud.google.com/go/longrunning v0.6.7 // indirect
|
||||
cloud.google.com/go/monitoring v1.24.2 // indirect
|
||||
cloud.google.com/go/spanner v1.84.1 // indirect
|
||||
cloud.google.com/go/storage v1.56.1 // indirect
|
||||
dario.cat/mergo v1.0.2 // indirect
|
||||
github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.3 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 // indirect
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.4.0 // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
|
||||
|
|
@ -88,18 +74,16 @@ require (
|
|||
github.com/aymerick/douceur v0.2.0 // indirect
|
||||
github.com/blang/semver v3.5.1+incompatible // indirect
|
||||
github.com/catppuccin/go v0.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/charmbracelet/bubbles v0.21.1-0.20250623103423-23b8fd6302d7 // indirect
|
||||
github.com/charmbracelet/bubbletea v1.3.6 // indirect
|
||||
github.com/charmbracelet/bubbletea v1.3.10 // indirect
|
||||
github.com/charmbracelet/colorprofile v0.3.1 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.9.3 // indirect
|
||||
github.com/charmbracelet/x/ansi v0.10.2 // indirect
|
||||
github.com/charmbracelet/x/cellbuf v0.0.13 // indirect
|
||||
github.com/charmbracelet/x/exp/slice v0.0.0-20250630141444-821143405392 // indirect
|
||||
github.com/charmbracelet/x/exp/strings v0.0.0-20250630141444-821143405392 // indirect
|
||||
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||
github.com/cli/browser v1.3.0 // indirect
|
||||
github.com/cli/shurcooL-graphql v0.0.4 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20251022180443-0feb69152e9f // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.18.1 // indirect
|
||||
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 // indirect
|
||||
github.com/danieljoos/wincred v1.2.2 // indirect
|
||||
|
|
@ -110,50 +94,39 @@ require (
|
|||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.9.3 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.35.0 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
|
||||
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/gdamore/encoding v1.0.1 // indirect
|
||||
github.com/go-chi/chi/v5 v5.2.3 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.1.3 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/analysis v0.23.0 // indirect
|
||||
github.com/go-openapi/errors v0.22.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.21.1 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/loads v0.22.0 // indirect
|
||||
github.com/go-openapi/runtime v0.28.0 // indirect
|
||||
github.com/go-openapi/spec v0.21.0 // indirect
|
||||
github.com/go-openapi/strfmt v0.23.0 // indirect
|
||||
github.com/go-openapi/swag v0.24.1 // indirect
|
||||
github.com/go-openapi/swag/cmdutils v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/conv v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/fileutils v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/jsonname v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/jsonutils v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/loading v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/mangling v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/netutils v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/stringutils v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/typeutils v0.24.0 // indirect
|
||||
github.com/go-openapi/swag/yamlutils v0.24.0 // indirect
|
||||
github.com/go-openapi/validate v0.24.0 // indirect
|
||||
github.com/go-openapi/analysis v0.24.1 // indirect
|
||||
github.com/go-openapi/errors v0.22.4 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.22.1 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.3 // indirect
|
||||
github.com/go-openapi/loads v0.23.2 // indirect
|
||||
github.com/go-openapi/runtime v0.29.2 // indirect
|
||||
github.com/go-openapi/spec v0.22.1 // indirect
|
||||
github.com/go-openapi/strfmt v0.25.0 // indirect
|
||||
github.com/go-openapi/swag v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/cmdutils v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/conv v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/fileutils v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/jsonname v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/jsonutils v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/loading v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/mangling v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/netutils v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/stringutils v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/typeutils v0.25.4 // indirect
|
||||
github.com/go-openapi/swag/yamlutils v0.25.4 // indirect
|
||||
github.com/go-openapi/validate v0.25.1 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/google/certificate-transparency-go v1.3.2 // indirect
|
||||
github.com/google/s2a-go v0.1.9 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.15.0 // indirect
|
||||
github.com/gorilla/css v1.0.1 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
|
||||
github.com/henvic/httpretty v0.1.4 // indirect
|
||||
github.com/huandu/xstrings v1.5.0 // indirect
|
||||
github.com/in-toto/in-toto-golang v0.9.0 // indirect
|
||||
|
|
@ -161,18 +134,14 @@ require (
|
|||
github.com/itchyny/gojq v0.12.17 // indirect
|
||||
github.com/itchyny/timefmt-go v0.1.6 // indirect
|
||||
github.com/jedisct1/go-minisign v0.0.0-20241212093149-d2f9f49435c7 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/klauspost/compress v1.18.1 // indirect
|
||||
github.com/letsencrypt/boulder v0.20250630.0 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.3.0 // indirect
|
||||
github.com/mailru/easyjson v0.9.0 // indirect
|
||||
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.17 // indirect
|
||||
github.com/microcosm-cc/bluemonday v1.0.27 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||
|
|
@ -181,65 +150,39 @@ require (
|
|||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.1 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
github.com/rodaine/table v1.3.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.9.0 // indirect
|
||||
github.com/sassoftware/relic v7.2.1+incompatible // indirect
|
||||
github.com/secure-systems-lab/go-securesystemslib v0.9.1 // indirect
|
||||
github.com/shibumi/go-pathspec v1.3.0 // indirect
|
||||
github.com/shopspring/decimal v1.4.0 // indirect
|
||||
github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466 // indirect
|
||||
github.com/sigstore/rekor v1.4.2 // indirect
|
||||
github.com/sigstore/rekor-tiles v0.1.11 // indirect
|
||||
github.com/sigstore/sigstore v1.9.6-0.20250729224751-181c5d3339b3 // indirect
|
||||
github.com/sigstore/timestamp-authority v1.2.9 // indirect
|
||||
github.com/sigstore/rekor v1.4.3 // indirect
|
||||
github.com/sigstore/rekor-tiles/v2 v2.0.1 // indirect
|
||||
github.com/sigstore/sigstore v1.10.0 // indirect
|
||||
github.com/sigstore/timestamp-authority/v2 v2.0.3 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.14.0 // indirect
|
||||
github.com/spf13/cast v1.9.2 // indirect
|
||||
github.com/spf13/viper v1.20.1 // indirect
|
||||
github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect
|
||||
github.com/spf13/cast v1.10.0 // indirect
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/theupdateframework/go-tuf v0.7.0 // indirect
|
||||
github.com/thlib/go-timezone-local v0.0.6 // indirect
|
||||
github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399 // indirect
|
||||
github.com/transparency-dev/formats v0.0.0-20250421220931-bb8ad4d07c26 // indirect
|
||||
github.com/transparency-dev/formats v0.0.0-20251017110053-404c0d5b696c // indirect
|
||||
github.com/transparency-dev/merkle v0.0.2 // indirect
|
||||
github.com/transparency-dev/tessera v1.0.0-rc3 // indirect
|
||||
github.com/vbatts/tar-split v0.12.2 // indirect
|
||||
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
|
||||
github.com/yuin/goldmark-emoji v1.0.6 // indirect
|
||||
go.mongodb.org/mongo-driver v1.17.4 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.mongodb.org/mongo-driver v1.17.6 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.38.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
|
||||
go.opentelemetry.io/otel v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.38.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
|
||||
golang.org/x/mod v0.30.0 // indirect
|
||||
golang.org/x/net v0.47.0 // indirect
|
||||
golang.org/x/oauth2 v0.33.0 // indirect
|
||||
golang.org/x/sys v0.39.0 // indirect
|
||||
golang.org/x/time v0.12.0 // indirect
|
||||
golang.org/x/tools v0.39.0 // indirect
|
||||
google.golang.org/api v0.248.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101 // indirect
|
||||
)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ jobs:
|
|||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- uses: cli/gh-extension-precompile@v2
|
||||
with:
|
||||
generate_attestations: true
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ jobs:
|
|||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- uses: cli/gh-extension-precompile@v2
|
||||
with:
|
||||
build_script_override: "script/build.sh"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# Manage go-licenses version externally for CI
|
||||
if [ "$CI" != "true" ]; then
|
||||
go install github.com/google/go-licenses@latest
|
||||
go install github.com/google/go-licenses/v2@latest
|
||||
fi
|
||||
|
||||
# Verify go-licenses is available
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# Manage go-licenses version externally for CI
|
||||
if [ "$CI" != "true" ]; then
|
||||
go install github.com/google/go-licenses@latest
|
||||
go install github.com/google/go-licenses/v2@latest
|
||||
fi
|
||||
|
||||
# Setup temporary directory for generated license reports
|
||||
|
|
|
|||
|
|
@ -8,23 +8,9 @@ Some packages may only be included on certain architectures or operating systems
|
|||
|
||||
|
||||
- [al.essio.dev/pkg/shellescape](https://pkg.go.dev/al.essio.dev/pkg/shellescape) ([MIT](https://github.com/alessio/shellescape/blob/v1.6.0/LICENSE))
|
||||
- [cel.dev/expr](https://pkg.go.dev/cel.dev/expr) ([Apache-2.0](https://github.com/google/cel-spec/blob/v0.24.0/LICENSE))
|
||||
- [cloud.google.com/go](https://pkg.go.dev/cloud.google.com/go) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/v0.121.6/LICENSE))
|
||||
- [cloud.google.com/go/auth](https://pkg.go.dev/cloud.google.com/go/auth) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/auth/v0.16.5/auth/LICENSE))
|
||||
- [cloud.google.com/go/auth/oauth2adapt](https://pkg.go.dev/cloud.google.com/go/auth/oauth2adapt) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/auth/oauth2adapt/v0.2.8/auth/oauth2adapt/LICENSE))
|
||||
- [cloud.google.com/go/compute/metadata](https://pkg.go.dev/cloud.google.com/go/compute/metadata) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/compute/metadata/v0.9.0/compute/metadata/LICENSE))
|
||||
- [cloud.google.com/go/iam](https://pkg.go.dev/cloud.google.com/go/iam) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/iam/v1.5.2/iam/LICENSE))
|
||||
- [cloud.google.com/go/longrunning](https://pkg.go.dev/cloud.google.com/go/longrunning) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/longrunning/v0.6.7/longrunning/LICENSE))
|
||||
- [cloud.google.com/go/monitoring](https://pkg.go.dev/cloud.google.com/go/monitoring) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/monitoring/v1.24.2/monitoring/LICENSE))
|
||||
- [cloud.google.com/go/spanner](https://pkg.go.dev/cloud.google.com/go/spanner) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/spanner/v1.84.1/spanner/LICENSE))
|
||||
- [cloud.google.com/go/storage](https://pkg.go.dev/cloud.google.com/go/storage) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/storage/v1.56.1/storage/LICENSE))
|
||||
- [dario.cat/mergo](https://pkg.go.dev/dario.cat/mergo) ([BSD-3-Clause](https://github.com/imdario/mergo/blob/v1.0.2/LICENSE))
|
||||
- [github.com/AlecAivazis/survey/v2](https://pkg.go.dev/github.com/AlecAivazis/survey/v2) ([MIT](https://github.com/AlecAivazis/survey/blob/v2.3.7/LICENSE))
|
||||
- [github.com/AlecAivazis/survey/v2/terminal](https://pkg.go.dev/github.com/AlecAivazis/survey/v2/terminal) ([MIT](https://github.com/AlecAivazis/survey/blob/v2.3.7/terminal/LICENSE.txt))
|
||||
- [github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp](https://pkg.go.dev/github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp) ([Apache-2.0](https://github.com/GoogleCloudPlatform/grpc-gcp-go/blob/grpcgcp/v1.5.3/grpcgcp/LICENSE))
|
||||
- [github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp](https://pkg.go.dev/github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp) ([Apache-2.0](https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/blob/detectors/gcp/v1.30.0/detectors/gcp/LICENSE))
|
||||
- [github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric](https://pkg.go.dev/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric) ([Apache-2.0](https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/blob/exporter/metric/v0.53.0/exporter/metric/LICENSE))
|
||||
- [github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping](https://pkg.go.dev/github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping) ([Apache-2.0](https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/blob/internal/resourcemapping/v0.53.0/internal/resourcemapping/LICENSE))
|
||||
- [github.com/MakeNowJust/heredoc](https://pkg.go.dev/github.com/MakeNowJust/heredoc) ([MIT](https://github.com/MakeNowJust/heredoc/blob/v1.0.0/LICENSE))
|
||||
- [github.com/Masterminds/goutils](https://pkg.go.dev/github.com/Masterminds/goutils) ([Apache-2.0](https://github.com/Masterminds/goutils/blob/v1.1.1/LICENSE.txt))
|
||||
- [github.com/Masterminds/semver/v3](https://pkg.go.dev/github.com/Masterminds/semver/v3) ([MIT](https://github.com/Masterminds/semver/blob/v3.4.0/LICENSE.txt))
|
||||
|
|
@ -39,14 +25,13 @@ Some packages may only be included on certain architectures or operating systems
|
|||
- [github.com/catppuccin/go](https://pkg.go.dev/github.com/catppuccin/go) ([MIT](https://github.com/catppuccin/go/blob/v0.3.0/LICENSE))
|
||||
- [github.com/cenkalti/backoff/v4](https://pkg.go.dev/github.com/cenkalti/backoff/v4) ([MIT](https://github.com/cenkalti/backoff/blob/v4.3.0/LICENSE))
|
||||
- [github.com/cenkalti/backoff/v5](https://pkg.go.dev/github.com/cenkalti/backoff/v5) ([MIT](https://github.com/cenkalti/backoff/blob/v5.0.3/LICENSE))
|
||||
- [github.com/cespare/xxhash/v2](https://pkg.go.dev/github.com/cespare/xxhash/v2) ([MIT](https://github.com/cespare/xxhash/blob/v2.3.0/LICENSE.txt))
|
||||
- [github.com/charmbracelet/bubbles](https://pkg.go.dev/github.com/charmbracelet/bubbles) ([MIT](https://github.com/charmbracelet/bubbles/blob/23b8fd6302d7/LICENSE))
|
||||
- [github.com/charmbracelet/bubbletea](https://pkg.go.dev/github.com/charmbracelet/bubbletea) ([MIT](https://github.com/charmbracelet/bubbletea/blob/v1.3.6/LICENSE))
|
||||
- [github.com/charmbracelet/bubbletea](https://pkg.go.dev/github.com/charmbracelet/bubbletea) ([MIT](https://github.com/charmbracelet/bubbletea/blob/v1.3.10/LICENSE))
|
||||
- [github.com/charmbracelet/colorprofile](https://pkg.go.dev/github.com/charmbracelet/colorprofile) ([MIT](https://github.com/charmbracelet/colorprofile/blob/v0.3.1/LICENSE))
|
||||
- [github.com/charmbracelet/glamour](https://pkg.go.dev/github.com/charmbracelet/glamour) ([MIT](https://github.com/charmbracelet/glamour/blob/v0.10.0/LICENSE))
|
||||
- [github.com/charmbracelet/huh](https://pkg.go.dev/github.com/charmbracelet/huh) ([MIT](https://github.com/charmbracelet/huh/blob/v0.8.0/LICENSE))
|
||||
- [github.com/charmbracelet/lipgloss](https://pkg.go.dev/github.com/charmbracelet/lipgloss) ([MIT](https://github.com/charmbracelet/lipgloss/blob/76690c660834/LICENSE))
|
||||
- [github.com/charmbracelet/x/ansi](https://pkg.go.dev/github.com/charmbracelet/x/ansi) ([MIT](https://github.com/charmbracelet/x/blob/ansi/v0.9.3/ansi/LICENSE))
|
||||
- [github.com/charmbracelet/x/ansi](https://pkg.go.dev/github.com/charmbracelet/x/ansi) ([MIT](https://github.com/charmbracelet/x/blob/ansi/v0.10.2/ansi/LICENSE))
|
||||
- [github.com/charmbracelet/x/cellbuf](https://pkg.go.dev/github.com/charmbracelet/x/cellbuf) ([MIT](https://github.com/charmbracelet/x/blob/cellbuf/v0.0.13/cellbuf/LICENSE))
|
||||
- [github.com/charmbracelet/x/exp/slice](https://pkg.go.dev/github.com/charmbracelet/x/exp/slice) ([MIT](https://github.com/charmbracelet/x/blob/821143405392/exp/slice/LICENSE))
|
||||
- [github.com/charmbracelet/x/exp/strings](https://pkg.go.dev/github.com/charmbracelet/x/exp/strings) ([MIT](https://github.com/charmbracelet/x/blob/821143405392/exp/strings/LICENSE))
|
||||
|
|
@ -56,10 +41,9 @@ Some packages may only be included on certain architectures or operating systems
|
|||
- [github.com/cli/oauth](https://pkg.go.dev/github.com/cli/oauth) ([MIT](https://github.com/cli/oauth/blob/v1.2.1/LICENSE))
|
||||
- [github.com/cli/safeexec](https://pkg.go.dev/github.com/cli/safeexec) ([BSD-2-Clause](https://github.com/cli/safeexec/blob/v1.0.1/LICENSE))
|
||||
- [github.com/cli/shurcooL-graphql](https://pkg.go.dev/github.com/cli/shurcooL-graphql) ([MIT](https://github.com/cli/shurcooL-graphql/blob/v0.0.4/LICENSE))
|
||||
- [github.com/cncf/xds/go](https://pkg.go.dev/github.com/cncf/xds/go) ([Apache-2.0](https://github.com/cncf/xds/blob/0feb69152e9f/go/LICENSE))
|
||||
- [github.com/containerd/stargz-snapshotter/estargz](https://pkg.go.dev/github.com/containerd/stargz-snapshotter/estargz) ([Apache-2.0](https://github.com/containerd/stargz-snapshotter/blob/estargz/v0.18.1/estargz/LICENSE))
|
||||
- [github.com/cpuguy83/go-md2man/v2/md2man](https://pkg.go.dev/github.com/cpuguy83/go-md2man/v2/md2man) ([MIT](https://github.com/cpuguy83/go-md2man/blob/v2.0.7/LICENSE.md))
|
||||
- [github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer](https://pkg.go.dev/github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer) ([Apache-2.0](https://github.com/cyberphone/json-canonicalization/blob/19d51d7fe467/LICENSE))
|
||||
- [github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer](https://pkg.go.dev/github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer) ([Unknown](Unknown))
|
||||
- [github.com/davecgh/go-spew/spew](https://pkg.go.dev/github.com/davecgh/go-spew/spew) ([ISC](https://github.com/davecgh/go-spew/blob/d8f796af33cc/LICENSE))
|
||||
- [github.com/digitorus/pkcs7](https://pkg.go.dev/github.com/digitorus/pkcs7) ([MIT](https://github.com/digitorus/pkcs7/blob/3a137a874352/LICENSE))
|
||||
- [github.com/digitorus/timestamp](https://pkg.go.dev/github.com/digitorus/timestamp) ([BSD-2-Clause](https://github.com/digitorus/timestamp/blob/c45532741eea/LICENSE))
|
||||
|
|
@ -69,84 +53,71 @@ Some packages may only be included on certain architectures or operating systems
|
|||
- [github.com/docker/distribution/registry/client/auth/challenge](https://pkg.go.dev/github.com/docker/distribution/registry/client/auth/challenge) ([Apache-2.0](https://github.com/docker/distribution/blob/v2.8.3/LICENSE))
|
||||
- [github.com/docker/docker-credential-helpers](https://pkg.go.dev/github.com/docker/docker-credential-helpers) ([MIT](https://github.com/docker/docker-credential-helpers/blob/v0.9.3/LICENSE))
|
||||
- [github.com/dustin/go-humanize](https://pkg.go.dev/github.com/dustin/go-humanize) ([MIT](https://github.com/dustin/go-humanize/blob/v1.0.1/LICENSE))
|
||||
- [github.com/envoyproxy/go-control-plane/envoy](https://pkg.go.dev/github.com/envoyproxy/go-control-plane/envoy) ([Apache-2.0](https://github.com/envoyproxy/go-control-plane/blob/envoy/v1.35.0/envoy/LICENSE))
|
||||
- [github.com/envoyproxy/protoc-gen-validate/validate](https://pkg.go.dev/github.com/envoyproxy/protoc-gen-validate/validate) ([Apache-2.0](https://github.com/envoyproxy/protoc-gen-validate/blob/v1.2.1/LICENSE))
|
||||
- [github.com/fatih/color](https://pkg.go.dev/github.com/fatih/color) ([MIT](https://github.com/fatih/color/blob/v1.18.0/LICENSE.md))
|
||||
- [github.com/felixge/httpsnoop](https://pkg.go.dev/github.com/felixge/httpsnoop) ([MIT](https://github.com/felixge/httpsnoop/blob/v1.0.4/LICENSE.txt))
|
||||
- [github.com/fsnotify/fsnotify](https://pkg.go.dev/github.com/fsnotify/fsnotify) ([BSD-3-Clause](https://github.com/fsnotify/fsnotify/blob/v1.9.0/LICENSE))
|
||||
- [github.com/gabriel-vasile/mimetype](https://pkg.go.dev/github.com/gabriel-vasile/mimetype) ([MIT](https://github.com/gabriel-vasile/mimetype/blob/v1.4.11/LICENSE))
|
||||
- [github.com/gdamore/encoding](https://pkg.go.dev/github.com/gdamore/encoding) ([Apache-2.0](https://github.com/gdamore/encoding/blob/v1.0.1/LICENSE))
|
||||
- [github.com/gdamore/tcell/v2](https://pkg.go.dev/github.com/gdamore/tcell/v2) ([Apache-2.0](https://github.com/gdamore/tcell/blob/v2.13.4/LICENSE))
|
||||
- [github.com/go-chi/chi/v5](https://pkg.go.dev/github.com/go-chi/chi/v5) ([MIT](https://github.com/go-chi/chi/blob/v5.2.3/LICENSE))
|
||||
- [github.com/go-jose/go-jose/v4](https://pkg.go.dev/github.com/go-jose/go-jose/v4) ([Apache-2.0](https://github.com/go-jose/go-jose/blob/v4.1.3/LICENSE))
|
||||
- [github.com/go-jose/go-jose/v4/json](https://pkg.go.dev/github.com/go-jose/go-jose/v4/json) ([BSD-3-Clause](https://github.com/go-jose/go-jose/blob/v4.1.3/json/LICENSE))
|
||||
- [github.com/go-logr/logr](https://pkg.go.dev/github.com/go-logr/logr) ([Apache-2.0](https://github.com/go-logr/logr/blob/v1.4.3/LICENSE))
|
||||
- [github.com/go-logr/stdr](https://pkg.go.dev/github.com/go-logr/stdr) ([Apache-2.0](https://github.com/go-logr/stdr/blob/v1.2.2/LICENSE))
|
||||
- [github.com/go-openapi/analysis](https://pkg.go.dev/github.com/go-openapi/analysis) ([Apache-2.0](https://github.com/go-openapi/analysis/blob/v0.23.0/LICENSE))
|
||||
- [github.com/go-openapi/errors](https://pkg.go.dev/github.com/go-openapi/errors) ([Apache-2.0](https://github.com/go-openapi/errors/blob/v0.22.2/LICENSE))
|
||||
- [github.com/go-openapi/jsonpointer](https://pkg.go.dev/github.com/go-openapi/jsonpointer) ([Apache-2.0](https://github.com/go-openapi/jsonpointer/blob/v0.21.1/LICENSE))
|
||||
- [github.com/go-openapi/jsonreference](https://pkg.go.dev/github.com/go-openapi/jsonreference) ([Apache-2.0](https://github.com/go-openapi/jsonreference/blob/v0.21.0/LICENSE))
|
||||
- [github.com/go-openapi/loads](https://pkg.go.dev/github.com/go-openapi/loads) ([Apache-2.0](https://github.com/go-openapi/loads/blob/v0.22.0/LICENSE))
|
||||
- [github.com/go-openapi/runtime](https://pkg.go.dev/github.com/go-openapi/runtime) ([Apache-2.0](https://github.com/go-openapi/runtime/blob/v0.28.0/LICENSE))
|
||||
- [github.com/go-openapi/runtime/middleware/denco](https://pkg.go.dev/github.com/go-openapi/runtime/middleware/denco) ([MIT](https://github.com/go-openapi/runtime/blob/v0.28.0/middleware/denco/LICENSE))
|
||||
- [github.com/go-openapi/spec](https://pkg.go.dev/github.com/go-openapi/spec) ([Apache-2.0](https://github.com/go-openapi/spec/blob/v0.21.0/LICENSE))
|
||||
- [github.com/go-openapi/strfmt](https://pkg.go.dev/github.com/go-openapi/strfmt) ([Apache-2.0](https://github.com/go-openapi/strfmt/blob/v0.23.0/LICENSE))
|
||||
- [github.com/go-openapi/swag](https://pkg.go.dev/github.com/go-openapi/swag) ([Apache-2.0](https://github.com/go-openapi/swag/blob/v0.24.1/LICENSE))
|
||||
- [github.com/go-openapi/swag/cmdutils](https://pkg.go.dev/github.com/go-openapi/swag/cmdutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/cmdutils/v0.24.0/cmdutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/conv](https://pkg.go.dev/github.com/go-openapi/swag/conv) ([Apache-2.0](https://github.com/go-openapi/swag/blob/conv/v0.24.0/conv/LICENSE))
|
||||
- [github.com/go-openapi/swag/fileutils](https://pkg.go.dev/github.com/go-openapi/swag/fileutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/fileutils/v0.24.0/fileutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/jsonname](https://pkg.go.dev/github.com/go-openapi/swag/jsonname) ([Apache-2.0](https://github.com/go-openapi/swag/blob/jsonname/v0.24.0/jsonname/LICENSE))
|
||||
- [github.com/go-openapi/swag/jsonutils](https://pkg.go.dev/github.com/go-openapi/swag/jsonutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/jsonutils/v0.24.0/jsonutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/loading](https://pkg.go.dev/github.com/go-openapi/swag/loading) ([Apache-2.0](https://github.com/go-openapi/swag/blob/loading/v0.24.0/loading/LICENSE))
|
||||
- [github.com/go-openapi/swag/mangling](https://pkg.go.dev/github.com/go-openapi/swag/mangling) ([Apache-2.0](https://github.com/go-openapi/swag/blob/mangling/v0.24.0/mangling/LICENSE))
|
||||
- [github.com/go-openapi/swag/netutils](https://pkg.go.dev/github.com/go-openapi/swag/netutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/netutils/v0.24.0/netutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/stringutils](https://pkg.go.dev/github.com/go-openapi/swag/stringutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/stringutils/v0.24.0/stringutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/typeutils](https://pkg.go.dev/github.com/go-openapi/swag/typeutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/typeutils/v0.24.0/typeutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/yamlutils](https://pkg.go.dev/github.com/go-openapi/swag/yamlutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/yamlutils/v0.24.0/yamlutils/LICENSE))
|
||||
- [github.com/go-openapi/validate](https://pkg.go.dev/github.com/go-openapi/validate) ([Apache-2.0](https://github.com/go-openapi/validate/blob/v0.24.0/LICENSE))
|
||||
- [github.com/go-openapi/analysis](https://pkg.go.dev/github.com/go-openapi/analysis) ([Apache-2.0](https://github.com/go-openapi/analysis/blob/v0.24.1/LICENSE))
|
||||
- [github.com/go-openapi/errors](https://pkg.go.dev/github.com/go-openapi/errors) ([Apache-2.0](https://github.com/go-openapi/errors/blob/v0.22.4/LICENSE))
|
||||
- [github.com/go-openapi/jsonpointer](https://pkg.go.dev/github.com/go-openapi/jsonpointer) ([Apache-2.0](https://github.com/go-openapi/jsonpointer/blob/v0.22.1/LICENSE))
|
||||
- [github.com/go-openapi/jsonreference](https://pkg.go.dev/github.com/go-openapi/jsonreference) ([Apache-2.0](https://github.com/go-openapi/jsonreference/blob/v0.21.3/LICENSE))
|
||||
- [github.com/go-openapi/loads](https://pkg.go.dev/github.com/go-openapi/loads) ([Apache-2.0](https://github.com/go-openapi/loads/blob/v0.23.2/LICENSE))
|
||||
- [github.com/go-openapi/runtime](https://pkg.go.dev/github.com/go-openapi/runtime) ([Apache-2.0](https://github.com/go-openapi/runtime/blob/v0.29.2/LICENSE))
|
||||
- [github.com/go-openapi/runtime/middleware/denco](https://pkg.go.dev/github.com/go-openapi/runtime/middleware/denco) ([MIT](https://github.com/go-openapi/runtime/blob/v0.29.2/middleware/denco/LICENSE))
|
||||
- [github.com/go-openapi/spec](https://pkg.go.dev/github.com/go-openapi/spec) ([Apache-2.0](https://github.com/go-openapi/spec/blob/v0.22.1/LICENSE))
|
||||
- [github.com/go-openapi/strfmt](https://pkg.go.dev/github.com/go-openapi/strfmt) ([Apache-2.0](https://github.com/go-openapi/strfmt/blob/v0.25.0/LICENSE))
|
||||
- [github.com/go-openapi/swag](https://pkg.go.dev/github.com/go-openapi/swag) ([Apache-2.0](https://github.com/go-openapi/swag/blob/v0.25.4/LICENSE))
|
||||
- [github.com/go-openapi/swag/cmdutils](https://pkg.go.dev/github.com/go-openapi/swag/cmdutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/cmdutils/v0.25.4/cmdutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/conv](https://pkg.go.dev/github.com/go-openapi/swag/conv) ([Apache-2.0](https://github.com/go-openapi/swag/blob/conv/v0.25.4/conv/LICENSE))
|
||||
- [github.com/go-openapi/swag/fileutils](https://pkg.go.dev/github.com/go-openapi/swag/fileutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/fileutils/v0.25.4/fileutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/jsonname](https://pkg.go.dev/github.com/go-openapi/swag/jsonname) ([Apache-2.0](https://github.com/go-openapi/swag/blob/jsonname/v0.25.4/jsonname/LICENSE))
|
||||
- [github.com/go-openapi/swag/jsonutils](https://pkg.go.dev/github.com/go-openapi/swag/jsonutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/jsonutils/v0.25.4/jsonutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/loading](https://pkg.go.dev/github.com/go-openapi/swag/loading) ([Apache-2.0](https://github.com/go-openapi/swag/blob/loading/v0.25.4/loading/LICENSE))
|
||||
- [github.com/go-openapi/swag/mangling](https://pkg.go.dev/github.com/go-openapi/swag/mangling) ([Apache-2.0](https://github.com/go-openapi/swag/blob/mangling/v0.25.4/mangling/LICENSE))
|
||||
- [github.com/go-openapi/swag/netutils](https://pkg.go.dev/github.com/go-openapi/swag/netutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/netutils/v0.25.4/netutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/stringutils](https://pkg.go.dev/github.com/go-openapi/swag/stringutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/stringutils/v0.25.4/stringutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/typeutils](https://pkg.go.dev/github.com/go-openapi/swag/typeutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/typeutils/v0.25.4/typeutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/yamlutils](https://pkg.go.dev/github.com/go-openapi/swag/yamlutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/yamlutils/v0.25.4/yamlutils/LICENSE))
|
||||
- [github.com/go-openapi/validate](https://pkg.go.dev/github.com/go-openapi/validate) ([Apache-2.0](https://github.com/go-openapi/validate/blob/v0.25.1/LICENSE))
|
||||
- [github.com/go-viper/mapstructure/v2](https://pkg.go.dev/github.com/go-viper/mapstructure/v2) ([MIT](https://github.com/go-viper/mapstructure/blob/v2.4.0/LICENSE))
|
||||
- [github.com/golang/groupcache/lru](https://pkg.go.dev/github.com/golang/groupcache/lru) ([Apache-2.0](https://github.com/golang/groupcache/blob/2c02b8208cf8/LICENSE))
|
||||
- [github.com/golang/snappy](https://pkg.go.dev/github.com/golang/snappy) ([BSD-3-Clause](https://github.com/golang/snappy/blob/v1.0.0/LICENSE))
|
||||
- [github.com/google/certificate-transparency-go](https://pkg.go.dev/github.com/google/certificate-transparency-go) ([Apache-2.0](https://github.com/google/certificate-transparency-go/blob/v1.3.2/LICENSE))
|
||||
- [github.com/google/go-cmp/cmp](https://pkg.go.dev/github.com/google/go-cmp/cmp) ([BSD-3-Clause](https://github.com/google/go-cmp/blob/v0.7.0/LICENSE))
|
||||
- [github.com/google/go-containerregistry](https://pkg.go.dev/github.com/google/go-containerregistry) ([Apache-2.0](https://github.com/google/go-containerregistry/blob/v0.20.7/LICENSE))
|
||||
- [github.com/google/s2a-go](https://pkg.go.dev/github.com/google/s2a-go) ([Apache-2.0](https://github.com/google/s2a-go/blob/v0.1.9/LICENSE.md))
|
||||
- [github.com/google/shlex](https://pkg.go.dev/github.com/google/shlex) ([Apache-2.0](https://github.com/google/shlex/blob/e7afc7fbc510/COPYING))
|
||||
- [github.com/google/uuid](https://pkg.go.dev/github.com/google/uuid) ([BSD-3-Clause](https://github.com/google/uuid/blob/v1.6.0/LICENSE))
|
||||
- [github.com/googleapis/enterprise-certificate-proxy/client](https://pkg.go.dev/github.com/googleapis/enterprise-certificate-proxy/client) ([Apache-2.0](https://github.com/googleapis/enterprise-certificate-proxy/blob/v0.3.6/LICENSE))
|
||||
- [github.com/googleapis/gax-go/v2](https://pkg.go.dev/github.com/googleapis/gax-go/v2) ([BSD-3-Clause](https://github.com/googleapis/gax-go/blob/v2.15.0/v2/LICENSE))
|
||||
- [github.com/gorilla/css/scanner](https://pkg.go.dev/github.com/gorilla/css/scanner) ([BSD-3-Clause](https://github.com/gorilla/css/blob/v1.0.1/LICENSE))
|
||||
- [github.com/gorilla/websocket](https://pkg.go.dev/github.com/gorilla/websocket) ([BSD-2-Clause](https://github.com/gorilla/websocket/blob/v1.5.3/LICENSE))
|
||||
- [github.com/grpc-ecosystem/grpc-gateway/v2](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/v2) ([BSD-3-Clause](https://github.com/grpc-ecosystem/grpc-gateway/blob/v2.27.2/LICENSE))
|
||||
- [github.com/grpc-ecosystem/grpc-gateway/v2](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/v2) ([BSD-3-Clause](https://github.com/grpc-ecosystem/grpc-gateway/blob/v2.27.3/LICENSE))
|
||||
- [github.com/hashicorp/go-version](https://pkg.go.dev/github.com/hashicorp/go-version) ([MPL-2.0](https://github.com/hashicorp/go-version/blob/v1.8.0/LICENSE))
|
||||
- [github.com/hashicorp/golang-lru/v2](https://pkg.go.dev/github.com/hashicorp/golang-lru/v2) ([MPL-2.0](https://github.com/hashicorp/golang-lru/blob/v2.0.7/LICENSE))
|
||||
- [github.com/hashicorp/golang-lru/v2/simplelru](https://pkg.go.dev/github.com/hashicorp/golang-lru/v2/simplelru) ([BSD-3-Clause](https://github.com/hashicorp/golang-lru/blob/v2.0.7/simplelru/LICENSE_list))
|
||||
- [github.com/henvic/httpretty](https://pkg.go.dev/github.com/henvic/httpretty) ([MIT](https://github.com/henvic/httpretty/blob/v0.1.4/LICENSE.md))
|
||||
- [github.com/huandu/xstrings](https://pkg.go.dev/github.com/huandu/xstrings) ([MIT](https://github.com/huandu/xstrings/blob/v1.5.0/LICENSE))
|
||||
- [github.com/in-toto/attestation/go/v1](https://pkg.go.dev/github.com/in-toto/attestation/go/v1) ([Apache-2.0](https://github.com/in-toto/attestation/blob/v1.1.2/LICENSE))
|
||||
- [github.com/in-toto/in-toto-golang/in_toto](https://pkg.go.dev/github.com/in-toto/in-toto-golang/in_toto) ([Apache-2.0](https://github.com/in-toto/in-toto-golang/blob/v0.9.0/LICENSE))
|
||||
- [github.com/in-toto/attestation/go/v1](https://pkg.go.dev/github.com/in-toto/attestation/go/v1) ([Unknown](Unknown))
|
||||
- [github.com/in-toto/in-toto-golang/in_toto](https://pkg.go.dev/github.com/in-toto/in-toto-golang/in_toto) ([Unknown](Unknown))
|
||||
- [github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common](https://pkg.go.dev/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common) ([Unknown](Unknown))
|
||||
- [github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.1](https://pkg.go.dev/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.1) ([Unknown](Unknown))
|
||||
- [github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2](https://pkg.go.dev/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2) ([Unknown](Unknown))
|
||||
- [github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1](https://pkg.go.dev/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1) ([Unknown](Unknown))
|
||||
- [github.com/itchyny/gojq](https://pkg.go.dev/github.com/itchyny/gojq) ([MIT](https://github.com/itchyny/gojq/blob/v0.12.17/LICENSE))
|
||||
- [github.com/itchyny/timefmt-go](https://pkg.go.dev/github.com/itchyny/timefmt-go) ([MIT](https://github.com/itchyny/timefmt-go/blob/v0.1.6/LICENSE))
|
||||
- [github.com/jedisct1/go-minisign](https://pkg.go.dev/github.com/jedisct1/go-minisign) ([MIT](https://github.com/jedisct1/go-minisign/blob/d2f9f49435c7/LICENSE))
|
||||
- [github.com/joho/godotenv](https://pkg.go.dev/github.com/joho/godotenv) ([MIT](https://github.com/joho/godotenv/blob/v1.5.1/LICENCE))
|
||||
- [github.com/josharian/intern](https://pkg.go.dev/github.com/josharian/intern) ([MIT](https://github.com/josharian/intern/blob/v1.0.0/license.md))
|
||||
- [github.com/kballard/go-shellquote](https://pkg.go.dev/github.com/kballard/go-shellquote) ([MIT](https://github.com/kballard/go-shellquote/blob/95032a82bc51/LICENSE))
|
||||
- [github.com/klauspost/compress](https://pkg.go.dev/github.com/klauspost/compress) ([MIT](https://github.com/klauspost/compress/blob/v1.18.1/LICENSE))
|
||||
- [github.com/klauspost/compress](https://pkg.go.dev/github.com/klauspost/compress) ([Apache-2.0](https://github.com/klauspost/compress/blob/v1.18.1/LICENSE))
|
||||
- [github.com/klauspost/compress](https://pkg.go.dev/github.com/klauspost/compress) ([BSD-3-Clause](https://github.com/klauspost/compress/blob/v1.18.1/LICENSE))
|
||||
- [github.com/klauspost/compress/internal/snapref](https://pkg.go.dev/github.com/klauspost/compress/internal/snapref) ([BSD-3-Clause](https://github.com/klauspost/compress/blob/v1.18.1/internal/snapref/LICENSE))
|
||||
- [github.com/klauspost/compress/zstd/internal/xxhash](https://pkg.go.dev/github.com/klauspost/compress/zstd/internal/xxhash) ([MIT](https://github.com/klauspost/compress/blob/v1.18.1/zstd/internal/xxhash/LICENSE.txt))
|
||||
- [github.com/letsencrypt/boulder](https://pkg.go.dev/github.com/letsencrypt/boulder) ([MPL-2.0](https://github.com/letsencrypt/boulder/blob/v0.20250630.0/LICENSE.txt))
|
||||
- [github.com/lucasb-eyer/go-colorful](https://pkg.go.dev/github.com/lucasb-eyer/go-colorful) ([MIT](https://github.com/lucasb-eyer/go-colorful/blob/v1.3.0/LICENSE))
|
||||
- [github.com/mailru/easyjson](https://pkg.go.dev/github.com/mailru/easyjson) ([MIT](https://github.com/mailru/easyjson/blob/v0.9.0/LICENSE))
|
||||
- [github.com/mattn/go-colorable](https://pkg.go.dev/github.com/mattn/go-colorable) ([MIT](https://github.com/mattn/go-colorable/blob/v0.1.14/LICENSE))
|
||||
- [github.com/mattn/go-isatty](https://pkg.go.dev/github.com/mattn/go-isatty) ([MIT](https://github.com/mattn/go-isatty/blob/v0.0.20/LICENSE))
|
||||
- [github.com/mattn/go-runewidth](https://pkg.go.dev/github.com/mattn/go-runewidth) ([MIT](https://github.com/mattn/go-runewidth/blob/v0.0.16/LICENSE))
|
||||
- [github.com/mattn/go-runewidth](https://pkg.go.dev/github.com/mattn/go-runewidth) ([MIT](https://github.com/mattn/go-runewidth/blob/v0.0.17/LICENSE))
|
||||
- [github.com/mgutz/ansi](https://pkg.go.dev/github.com/mgutz/ansi) ([MIT](https://github.com/mgutz/ansi/blob/d51e80ef957d/LICENSE))
|
||||
- [github.com/microcosm-cc/bluemonday](https://pkg.go.dev/github.com/microcosm-cc/bluemonday) ([BSD-3-Clause](https://github.com/microcosm-cc/bluemonday/blob/v1.0.27/LICENSE.md))
|
||||
- [github.com/microsoft/dev-tunnels/go/tunnels](https://pkg.go.dev/github.com/microsoft/dev-tunnels/go/tunnels) ([MIT](https://github.com/microsoft/dev-tunnels/blob/v0.1.19/LICENSE))
|
||||
- [github.com/mitchellh/copystructure](https://pkg.go.dev/github.com/mitchellh/copystructure) ([MIT](https://github.com/mitchellh/copystructure/blob/v1.2.0/LICENSE))
|
||||
- [github.com/mitchellh/go-homedir](https://pkg.go.dev/github.com/mitchellh/go-homedir) ([MIT](https://github.com/mitchellh/go-homedir/blob/v1.1.0/LICENSE))
|
||||
- [github.com/mitchellh/hashstructure/v2](https://pkg.go.dev/github.com/mitchellh/hashstructure/v2) ([MIT](https://github.com/mitchellh/hashstructure/blob/v2.0.2/LICENSE))
|
||||
- [github.com/mitchellh/mapstructure](https://pkg.go.dev/github.com/mitchellh/mapstructure) ([MIT](https://github.com/mitchellh/mapstructure/blob/v1.5.0/LICENSE))
|
||||
- [github.com/mitchellh/reflectwalk](https://pkg.go.dev/github.com/mitchellh/reflectwalk) ([MIT](https://github.com/mitchellh/reflectwalk/blob/v1.0.2/LICENSE))
|
||||
- [github.com/muesli/ansi](https://pkg.go.dev/github.com/muesli/ansi) ([MIT](https://github.com/muesli/ansi/blob/276c6243b2f6/LICENSE))
|
||||
- [github.com/muesli/cancelreader](https://pkg.go.dev/github.com/muesli/cancelreader) ([MIT](https://github.com/muesli/cancelreader/blob/v0.2.2/LICENSE))
|
||||
|
|
@ -157,83 +128,60 @@ Some packages may only be included on certain architectures or operating systems
|
|||
- [github.com/opencontainers/go-digest](https://pkg.go.dev/github.com/opencontainers/go-digest) ([Apache-2.0](https://github.com/opencontainers/go-digest/blob/v1.0.0/LICENSE))
|
||||
- [github.com/opencontainers/image-spec/specs-go](https://pkg.go.dev/github.com/opencontainers/image-spec/specs-go) ([Apache-2.0](https://github.com/opencontainers/image-spec/blob/v1.1.1/LICENSE))
|
||||
- [github.com/opentracing/opentracing-go](https://pkg.go.dev/github.com/opentracing/opentracing-go) ([Apache-2.0](https://github.com/opentracing/opentracing-go/blob/v1.2.0/LICENSE))
|
||||
- [github.com/pelletier/go-toml/v2](https://pkg.go.dev/github.com/pelletier/go-toml/v2) ([MIT](https://github.com/pelletier/go-toml/blob/v2.2.4/LICENSE))
|
||||
- [github.com/pkg/errors](https://pkg.go.dev/github.com/pkg/errors) ([BSD-2-Clause](https://github.com/pkg/errors/blob/v0.9.1/LICENSE))
|
||||
- [github.com/pmezard/go-difflib/difflib](https://pkg.go.dev/github.com/pmezard/go-difflib/difflib) ([BSD-3-Clause](https://github.com/pmezard/go-difflib/blob/5d4384ee4fb2/LICENSE))
|
||||
- [github.com/rivo/tview](https://pkg.go.dev/github.com/rivo/tview) ([MIT](https://github.com/rivo/tview/blob/v0.42.0/LICENSE.txt))
|
||||
- [github.com/rivo/uniseg](https://pkg.go.dev/github.com/rivo/uniseg) ([MIT](https://github.com/rivo/uniseg/blob/v0.4.7/LICENSE.txt))
|
||||
- [github.com/rodaine/table](https://pkg.go.dev/github.com/rodaine/table) ([MIT](https://github.com/rodaine/table/blob/v1.3.0/license))
|
||||
- [github.com/russross/blackfriday/v2](https://pkg.go.dev/github.com/russross/blackfriday/v2) ([BSD-2-Clause](https://github.com/russross/blackfriday/blob/v2.1.0/LICENSE.txt))
|
||||
- [github.com/sagikazarmark/locafero](https://pkg.go.dev/github.com/sagikazarmark/locafero) ([MIT](https://github.com/sagikazarmark/locafero/blob/v0.9.0/LICENSE))
|
||||
- [github.com/sassoftware/relic/lib](https://pkg.go.dev/github.com/sassoftware/relic/lib) ([Apache-2.0](https://github.com/sassoftware/relic/blob/v7.2.1/LICENSE))
|
||||
- [github.com/secure-systems-lab/go-securesystemslib](https://pkg.go.dev/github.com/secure-systems-lab/go-securesystemslib) ([MIT](https://github.com/secure-systems-lab/go-securesystemslib/blob/v0.9.1/LICENSE))
|
||||
- [github.com/shibumi/go-pathspec](https://pkg.go.dev/github.com/shibumi/go-pathspec) ([Apache-2.0](https://github.com/shibumi/go-pathspec/blob/v1.3.0/LICENSE))
|
||||
- [github.com/shopspring/decimal](https://pkg.go.dev/github.com/shopspring/decimal) ([MIT](https://github.com/shopspring/decimal/blob/v1.4.0/LICENSE))
|
||||
- [github.com/shurcooL/githubv4](https://pkg.go.dev/github.com/shurcooL/githubv4) ([MIT](https://github.com/shurcooL/githubv4/blob/48295856cce7/LICENSE))
|
||||
- [github.com/shurcooL/graphql](https://pkg.go.dev/github.com/shurcooL/graphql) ([MIT](https://github.com/shurcooL/graphql/blob/ed46e5a46466/LICENSE))
|
||||
- [github.com/sigstore/protobuf-specs/gen/pb-go](https://pkg.go.dev/github.com/sigstore/protobuf-specs/gen/pb-go) ([Apache-2.0](https://github.com/sigstore/protobuf-specs/blob/v0.5.0/LICENSE))
|
||||
- [github.com/sigstore/rekor-tiles](https://pkg.go.dev/github.com/sigstore/rekor-tiles) ([Apache-2.0](https://github.com/sigstore/rekor-tiles/blob/v0.1.11/LICENSE))
|
||||
- [github.com/sigstore/rekor/pkg](https://pkg.go.dev/github.com/sigstore/rekor/pkg) ([Apache-2.0](https://github.com/sigstore/rekor/blob/v1.4.2/LICENSE))
|
||||
- [github.com/sigstore/sigstore-go/pkg](https://pkg.go.dev/github.com/sigstore/sigstore-go/pkg) ([Apache-2.0](https://github.com/sigstore/sigstore-go/blob/v1.1.3/LICENSE))
|
||||
- [github.com/sigstore/sigstore/pkg](https://pkg.go.dev/github.com/sigstore/sigstore/pkg) ([Apache-2.0](https://github.com/sigstore/sigstore/blob/181c5d3339b3/LICENSE))
|
||||
- [github.com/sigstore/timestamp-authority/pkg/verification](https://pkg.go.dev/github.com/sigstore/timestamp-authority/pkg/verification) ([Apache-2.0](https://github.com/sigstore/timestamp-authority/blob/v1.2.9/LICENSE))
|
||||
- [github.com/sigstore/rekor-tiles/v2](https://pkg.go.dev/github.com/sigstore/rekor-tiles/v2) ([Apache-2.0](https://github.com/sigstore/rekor-tiles/blob/v2.0.1/LICENSE))
|
||||
- [github.com/sigstore/rekor/pkg](https://pkg.go.dev/github.com/sigstore/rekor/pkg) ([Apache-2.0](https://github.com/sigstore/rekor/blob/v1.4.3/LICENSE))
|
||||
- [github.com/sigstore/sigstore-go/pkg](https://pkg.go.dev/github.com/sigstore/sigstore-go/pkg) ([Apache-2.0](https://github.com/sigstore/sigstore-go/blob/v1.1.4/LICENSE))
|
||||
- [github.com/sigstore/sigstore/pkg](https://pkg.go.dev/github.com/sigstore/sigstore/pkg) ([Apache-2.0](https://github.com/sigstore/sigstore/blob/v1.10.0/LICENSE))
|
||||
- [github.com/sigstore/timestamp-authority/v2/pkg/verification](https://pkg.go.dev/github.com/sigstore/timestamp-authority/v2/pkg/verification) ([Apache-2.0](https://github.com/sigstore/timestamp-authority/blob/v2.0.3/LICENSE))
|
||||
- [github.com/sirupsen/logrus](https://pkg.go.dev/github.com/sirupsen/logrus) ([MIT](https://github.com/sirupsen/logrus/blob/v1.9.3/LICENSE))
|
||||
- [github.com/sourcegraph/conc](https://pkg.go.dev/github.com/sourcegraph/conc) ([MIT](https://github.com/sourcegraph/conc/blob/v0.3.0/LICENSE))
|
||||
- [github.com/spf13/afero](https://pkg.go.dev/github.com/spf13/afero) ([Apache-2.0](https://github.com/spf13/afero/blob/v1.14.0/LICENSE.txt))
|
||||
- [github.com/spf13/cast](https://pkg.go.dev/github.com/spf13/cast) ([MIT](https://github.com/spf13/cast/blob/v1.9.2/LICENSE))
|
||||
- [github.com/spf13/cast](https://pkg.go.dev/github.com/spf13/cast) ([MIT](https://github.com/spf13/cast/blob/v1.10.0/LICENSE))
|
||||
- [github.com/spf13/cobra](https://pkg.go.dev/github.com/spf13/cobra) ([Apache-2.0](https://github.com/spf13/cobra/blob/v1.10.2/LICENSE.txt))
|
||||
- [github.com/spf13/pflag](https://pkg.go.dev/github.com/spf13/pflag) ([BSD-3-Clause](https://github.com/spf13/pflag/blob/v1.0.10/LICENSE))
|
||||
- [github.com/spf13/viper](https://pkg.go.dev/github.com/spf13/viper) ([MIT](https://github.com/spf13/viper/blob/v1.20.1/LICENSE))
|
||||
- [github.com/spiffe/go-spiffe/v2](https://pkg.go.dev/github.com/spiffe/go-spiffe/v2) ([Apache-2.0](https://github.com/spiffe/go-spiffe/blob/v2.6.0/LICENSE))
|
||||
- [github.com/stretchr/objx](https://pkg.go.dev/github.com/stretchr/objx) ([MIT](https://github.com/stretchr/objx/blob/v0.5.2/LICENSE))
|
||||
- [github.com/stretchr/testify](https://pkg.go.dev/github.com/stretchr/testify) ([MIT](https://github.com/stretchr/testify/blob/v1.11.1/LICENSE))
|
||||
- [github.com/subosito/gotenv](https://pkg.go.dev/github.com/subosito/gotenv) ([MIT](https://github.com/subosito/gotenv/blob/v1.6.0/LICENSE))
|
||||
- [github.com/theupdateframework/go-tuf](https://pkg.go.dev/github.com/theupdateframework/go-tuf) ([BSD-3-Clause](https://github.com/theupdateframework/go-tuf/blob/v0.7.0/LICENSE))
|
||||
- [github.com/theupdateframework/go-tuf/v2/metadata](https://pkg.go.dev/github.com/theupdateframework/go-tuf/v2/metadata) ([Apache-2.0](https://github.com/theupdateframework/go-tuf/blob/v2.3.0/LICENSE))
|
||||
- [github.com/thlib/go-timezone-local/tzlocal](https://pkg.go.dev/github.com/thlib/go-timezone-local/tzlocal) ([Unlicense](https://github.com/thlib/go-timezone-local/blob/v0.0.6/LICENSE))
|
||||
- [github.com/titanous/rocacheck](https://pkg.go.dev/github.com/titanous/rocacheck) ([MIT](https://github.com/titanous/rocacheck/blob/afe73141d399/LICENSE))
|
||||
- [github.com/transparency-dev/formats](https://pkg.go.dev/github.com/transparency-dev/formats) ([Apache-2.0](https://github.com/transparency-dev/formats/blob/bb8ad4d07c26/LICENSE))
|
||||
- [github.com/transparency-dev/formats/log](https://pkg.go.dev/github.com/transparency-dev/formats/log) ([Apache-2.0](https://github.com/transparency-dev/formats/blob/404c0d5b696c/LICENSE))
|
||||
- [github.com/transparency-dev/merkle](https://pkg.go.dev/github.com/transparency-dev/merkle) ([Apache-2.0](https://github.com/transparency-dev/merkle/blob/v0.0.2/LICENSE))
|
||||
- [github.com/transparency-dev/tessera](https://pkg.go.dev/github.com/transparency-dev/tessera) ([Apache-2.0](https://github.com/transparency-dev/tessera/blob/v1.0.0-rc3/LICENSE))
|
||||
- [github.com/vbatts/tar-split/archive/tar](https://pkg.go.dev/github.com/vbatts/tar-split/archive/tar) ([BSD-3-Clause](https://github.com/vbatts/tar-split/blob/v0.12.2/LICENSE))
|
||||
- [github.com/vmihailenco/msgpack/v5](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5) ([BSD-2-Clause](https://github.com/vmihailenco/msgpack/blob/v5.4.1/LICENSE))
|
||||
- [github.com/vmihailenco/tagparser/v2](https://pkg.go.dev/github.com/vmihailenco/tagparser/v2) ([BSD-2-Clause](https://github.com/vmihailenco/tagparser/blob/v2.0.0/LICENSE))
|
||||
- [github.com/xo/terminfo](https://pkg.go.dev/github.com/xo/terminfo) ([MIT](https://github.com/xo/terminfo/blob/abceb7e1c41e/LICENSE))
|
||||
- [github.com/yuin/goldmark](https://pkg.go.dev/github.com/yuin/goldmark) ([MIT](https://github.com/yuin/goldmark/blob/v1.7.13/LICENSE))
|
||||
- [github.com/yuin/goldmark](https://pkg.go.dev/github.com/yuin/goldmark) ([MIT](https://github.com/yuin/goldmark/blob/v1.7.16/LICENSE))
|
||||
- [github.com/yuin/goldmark-emoji](https://pkg.go.dev/github.com/yuin/goldmark-emoji) ([MIT](https://github.com/yuin/goldmark-emoji/blob/v1.0.6/LICENSE))
|
||||
- [github.com/zalando/go-keyring](https://pkg.go.dev/github.com/zalando/go-keyring) ([MIT](https://github.com/zalando/go-keyring/blob/v0.2.6/LICENSE))
|
||||
- [go.mongodb.org/mongo-driver](https://pkg.go.dev/go.mongodb.org/mongo-driver) ([Apache-2.0](https://github.com/mongodb/mongo-go-driver/blob/v1.17.4/LICENSE))
|
||||
- [go.opencensus.io](https://pkg.go.dev/go.opencensus.io) ([Apache-2.0](https://github.com/census-instrumentation/opencensus-go/blob/v0.24.0/LICENSE))
|
||||
- [go.mongodb.org/mongo-driver](https://pkg.go.dev/go.mongodb.org/mongo-driver) ([Apache-2.0](https://github.com/mongodb/mongo-go-driver/blob/v1.17.6/LICENSE))
|
||||
- [go.opentelemetry.io/auto/sdk](https://pkg.go.dev/go.opentelemetry.io/auto/sdk) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go-instrumentation/blob/sdk/v1.2.1/sdk/LICENSE))
|
||||
- [go.opentelemetry.io/contrib/detectors/gcp](https://pkg.go.dev/go.opentelemetry.io/contrib/detectors/gcp) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/detectors/gcp/v1.38.0/detectors/gcp/LICENSE))
|
||||
- [go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc](https://pkg.go.dev/go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/instrumentation/google.golang.org/grpc/otelgrpc/v0.61.0/instrumentation/google.golang.org/grpc/otelgrpc/LICENSE))
|
||||
- [go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp](https://pkg.go.dev/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/instrumentation/net/http/otelhttp/v0.61.0/instrumentation/net/http/otelhttp/LICENSE))
|
||||
- [go.opentelemetry.io/otel](https://pkg.go.dev/go.opentelemetry.io/otel) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go/blob/v1.38.0/LICENSE))
|
||||
- [go.opentelemetry.io/otel](https://pkg.go.dev/go.opentelemetry.io/otel) ([BSD-3-Clause](https://github.com/open-telemetry/opentelemetry-go/blob/v1.38.0/LICENSE))
|
||||
- [go.opentelemetry.io/otel/metric](https://pkg.go.dev/go.opentelemetry.io/otel/metric) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go/blob/metric/v1.38.0/metric/LICENSE))
|
||||
- [go.opentelemetry.io/otel/sdk](https://pkg.go.dev/go.opentelemetry.io/otel/sdk) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go/blob/sdk/v1.38.0/sdk/LICENSE))
|
||||
- [go.opentelemetry.io/otel/sdk/metric](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/metric) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go/blob/sdk/metric/v1.38.0/sdk/metric/LICENSE))
|
||||
- [go.opentelemetry.io/otel/metric](https://pkg.go.dev/go.opentelemetry.io/otel/metric) ([BSD-3-Clause](https://github.com/open-telemetry/opentelemetry-go/blob/metric/v1.38.0/metric/LICENSE))
|
||||
- [go.opentelemetry.io/otel/trace](https://pkg.go.dev/go.opentelemetry.io/otel/trace) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go/blob/trace/v1.38.0/trace/LICENSE))
|
||||
- [go.uber.org/multierr](https://pkg.go.dev/go.uber.org/multierr) ([MIT](https://github.com/uber-go/multierr/blob/v1.11.0/LICENSE.txt))
|
||||
- [go.uber.org/zap](https://pkg.go.dev/go.uber.org/zap) ([MIT](https://github.com/uber-go/zap/blob/v1.27.0/LICENSE))
|
||||
- [go.opentelemetry.io/otel/trace](https://pkg.go.dev/go.opentelemetry.io/otel/trace) ([BSD-3-Clause](https://github.com/open-telemetry/opentelemetry-go/blob/trace/v1.38.0/trace/LICENSE))
|
||||
- [go.yaml.in/yaml/v3](https://pkg.go.dev/go.yaml.in/yaml/v3) ([MIT](https://github.com/yaml/go-yaml/blob/v3.0.4/LICENSE))
|
||||
- [golang.org/x/crypto](https://pkg.go.dev/golang.org/x/crypto) ([BSD-3-Clause](https://cs.opensource.google/go/x/crypto/+/v0.46.0:LICENSE))
|
||||
- [golang.org/x/exp](https://pkg.go.dev/golang.org/x/exp) ([BSD-3-Clause](https://cs.opensource.google/go/x/exp/+/b7579e27:LICENSE))
|
||||
- [golang.org/x/mod](https://pkg.go.dev/golang.org/x/mod) ([BSD-3-Clause](https://cs.opensource.google/go/x/mod/+/v0.30.0:LICENSE))
|
||||
- [golang.org/x/net](https://pkg.go.dev/golang.org/x/net) ([BSD-3-Clause](https://cs.opensource.google/go/x/net/+/v0.47.0:LICENSE))
|
||||
- [golang.org/x/oauth2](https://pkg.go.dev/golang.org/x/oauth2) ([BSD-3-Clause](https://cs.opensource.google/go/x/oauth2/+/v0.33.0:LICENSE))
|
||||
- [golang.org/x/sync](https://pkg.go.dev/golang.org/x/sync) ([BSD-3-Clause](https://cs.opensource.google/go/x/sync/+/v0.19.0:LICENSE))
|
||||
- [golang.org/x/sync/errgroup](https://pkg.go.dev/golang.org/x/sync/errgroup) ([BSD-3-Clause](https://cs.opensource.google/go/x/sync/+/v0.19.0:LICENSE))
|
||||
- [golang.org/x/sys](https://pkg.go.dev/golang.org/x/sys) ([BSD-3-Clause](https://cs.opensource.google/go/x/sys/+/v0.39.0:LICENSE))
|
||||
- [golang.org/x/term](https://pkg.go.dev/golang.org/x/term) ([BSD-3-Clause](https://cs.opensource.google/go/x/term/+/v0.38.0:LICENSE))
|
||||
- [golang.org/x/text](https://pkg.go.dev/golang.org/x/text) ([BSD-3-Clause](https://cs.opensource.google/go/x/text/+/v0.32.0:LICENSE))
|
||||
- [golang.org/x/time/rate](https://pkg.go.dev/golang.org/x/time/rate) ([BSD-3-Clause](https://cs.opensource.google/go/x/time/+/v0.12.0:LICENSE))
|
||||
- [google.golang.org/api](https://pkg.go.dev/google.golang.org/api) ([BSD-3-Clause](https://github.com/googleapis/google-api-go-client/blob/v0.248.0/LICENSE))
|
||||
- [google.golang.org/api/internal/third_party/uritemplates](https://pkg.go.dev/google.golang.org/api/internal/third_party/uritemplates) ([BSD-3-Clause](https://github.com/googleapis/google-api-go-client/blob/v0.248.0/internal/third_party/uritemplates/LICENSE))
|
||||
- [google.golang.org/genproto/googleapis/api](https://pkg.go.dev/google.golang.org/genproto/googleapis/api) ([Apache-2.0](https://github.com/googleapis/go-genproto/blob/3a174f9686a8/googleapis/api/LICENSE))
|
||||
- [google.golang.org/genproto/googleapis/rpc](https://pkg.go.dev/google.golang.org/genproto/googleapis/rpc) ([Apache-2.0](https://github.com/googleapis/go-genproto/blob/3a174f9686a8/googleapis/rpc/LICENSE))
|
||||
- [google.golang.org/genproto/googleapis/type](https://pkg.go.dev/google.golang.org/genproto/googleapis/type) ([Apache-2.0](https://github.com/googleapis/go-genproto/blob/513f23925822/LICENSE))
|
||||
- [google.golang.org/genproto/googleapis/rpc/status](https://pkg.go.dev/google.golang.org/genproto/googleapis/rpc/status) ([Apache-2.0](https://github.com/googleapis/go-genproto/blob/f26f9409b101/googleapis/rpc/LICENSE))
|
||||
- [google.golang.org/grpc](https://pkg.go.dev/google.golang.org/grpc) ([Apache-2.0](https://github.com/grpc/grpc-go/blob/v1.77.0/LICENSE))
|
||||
- [google.golang.org/protobuf](https://pkg.go.dev/google.golang.org/protobuf) ([BSD-3-Clause](https://github.com/protocolbuffers/protobuf-go/blob/v1.36.10/LICENSE))
|
||||
- [gopkg.in/yaml.v3](https://pkg.go.dev/gopkg.in/yaml.v3) ([MIT](https://github.com/go-yaml/yaml/blob/v3.0.1/LICENSE))
|
||||
- [k8s.io/klog/v2](https://pkg.go.dev/k8s.io/klog/v2) ([Apache-2.0](https://github.com/kubernetes/klog/blob/v2.130.1/LICENSE))
|
||||
|
||||
[cli/cli]: https://github.com/cli/cli
|
||||
|
|
|
|||
|
|
@ -7,23 +7,9 @@ The following open source dependencies are used to build the [cli/cli][] GitHub
|
|||
Some packages may only be included on certain architectures or operating systems.
|
||||
|
||||
|
||||
- [cel.dev/expr](https://pkg.go.dev/cel.dev/expr) ([Apache-2.0](https://github.com/google/cel-spec/blob/v0.24.0/LICENSE))
|
||||
- [cloud.google.com/go](https://pkg.go.dev/cloud.google.com/go) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/v0.121.6/LICENSE))
|
||||
- [cloud.google.com/go/auth](https://pkg.go.dev/cloud.google.com/go/auth) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/auth/v0.16.5/auth/LICENSE))
|
||||
- [cloud.google.com/go/auth/oauth2adapt](https://pkg.go.dev/cloud.google.com/go/auth/oauth2adapt) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/auth/oauth2adapt/v0.2.8/auth/oauth2adapt/LICENSE))
|
||||
- [cloud.google.com/go/compute/metadata](https://pkg.go.dev/cloud.google.com/go/compute/metadata) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/compute/metadata/v0.9.0/compute/metadata/LICENSE))
|
||||
- [cloud.google.com/go/iam](https://pkg.go.dev/cloud.google.com/go/iam) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/iam/v1.5.2/iam/LICENSE))
|
||||
- [cloud.google.com/go/longrunning](https://pkg.go.dev/cloud.google.com/go/longrunning) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/longrunning/v0.6.7/longrunning/LICENSE))
|
||||
- [cloud.google.com/go/monitoring](https://pkg.go.dev/cloud.google.com/go/monitoring) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/monitoring/v1.24.2/monitoring/LICENSE))
|
||||
- [cloud.google.com/go/spanner](https://pkg.go.dev/cloud.google.com/go/spanner) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/spanner/v1.84.1/spanner/LICENSE))
|
||||
- [cloud.google.com/go/storage](https://pkg.go.dev/cloud.google.com/go/storage) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/storage/v1.56.1/storage/LICENSE))
|
||||
- [dario.cat/mergo](https://pkg.go.dev/dario.cat/mergo) ([BSD-3-Clause](https://github.com/imdario/mergo/blob/v1.0.2/LICENSE))
|
||||
- [github.com/AlecAivazis/survey/v2](https://pkg.go.dev/github.com/AlecAivazis/survey/v2) ([MIT](https://github.com/AlecAivazis/survey/blob/v2.3.7/LICENSE))
|
||||
- [github.com/AlecAivazis/survey/v2/terminal](https://pkg.go.dev/github.com/AlecAivazis/survey/v2/terminal) ([MIT](https://github.com/AlecAivazis/survey/blob/v2.3.7/terminal/LICENSE.txt))
|
||||
- [github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp](https://pkg.go.dev/github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp) ([Apache-2.0](https://github.com/GoogleCloudPlatform/grpc-gcp-go/blob/grpcgcp/v1.5.3/grpcgcp/LICENSE))
|
||||
- [github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp](https://pkg.go.dev/github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp) ([Apache-2.0](https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/blob/detectors/gcp/v1.30.0/detectors/gcp/LICENSE))
|
||||
- [github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric](https://pkg.go.dev/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric) ([Apache-2.0](https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/blob/exporter/metric/v0.53.0/exporter/metric/LICENSE))
|
||||
- [github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping](https://pkg.go.dev/github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping) ([Apache-2.0](https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/blob/internal/resourcemapping/v0.53.0/internal/resourcemapping/LICENSE))
|
||||
- [github.com/MakeNowJust/heredoc](https://pkg.go.dev/github.com/MakeNowJust/heredoc) ([MIT](https://github.com/MakeNowJust/heredoc/blob/v1.0.0/LICENSE))
|
||||
- [github.com/Masterminds/goutils](https://pkg.go.dev/github.com/Masterminds/goutils) ([Apache-2.0](https://github.com/Masterminds/goutils/blob/v1.1.1/LICENSE.txt))
|
||||
- [github.com/Masterminds/semver/v3](https://pkg.go.dev/github.com/Masterminds/semver/v3) ([MIT](https://github.com/Masterminds/semver/blob/v3.4.0/LICENSE.txt))
|
||||
|
|
@ -38,14 +24,13 @@ Some packages may only be included on certain architectures or operating systems
|
|||
- [github.com/catppuccin/go](https://pkg.go.dev/github.com/catppuccin/go) ([MIT](https://github.com/catppuccin/go/blob/v0.3.0/LICENSE))
|
||||
- [github.com/cenkalti/backoff/v4](https://pkg.go.dev/github.com/cenkalti/backoff/v4) ([MIT](https://github.com/cenkalti/backoff/blob/v4.3.0/LICENSE))
|
||||
- [github.com/cenkalti/backoff/v5](https://pkg.go.dev/github.com/cenkalti/backoff/v5) ([MIT](https://github.com/cenkalti/backoff/blob/v5.0.3/LICENSE))
|
||||
- [github.com/cespare/xxhash/v2](https://pkg.go.dev/github.com/cespare/xxhash/v2) ([MIT](https://github.com/cespare/xxhash/blob/v2.3.0/LICENSE.txt))
|
||||
- [github.com/charmbracelet/bubbles](https://pkg.go.dev/github.com/charmbracelet/bubbles) ([MIT](https://github.com/charmbracelet/bubbles/blob/23b8fd6302d7/LICENSE))
|
||||
- [github.com/charmbracelet/bubbletea](https://pkg.go.dev/github.com/charmbracelet/bubbletea) ([MIT](https://github.com/charmbracelet/bubbletea/blob/v1.3.6/LICENSE))
|
||||
- [github.com/charmbracelet/bubbletea](https://pkg.go.dev/github.com/charmbracelet/bubbletea) ([MIT](https://github.com/charmbracelet/bubbletea/blob/v1.3.10/LICENSE))
|
||||
- [github.com/charmbracelet/colorprofile](https://pkg.go.dev/github.com/charmbracelet/colorprofile) ([MIT](https://github.com/charmbracelet/colorprofile/blob/v0.3.1/LICENSE))
|
||||
- [github.com/charmbracelet/glamour](https://pkg.go.dev/github.com/charmbracelet/glamour) ([MIT](https://github.com/charmbracelet/glamour/blob/v0.10.0/LICENSE))
|
||||
- [github.com/charmbracelet/huh](https://pkg.go.dev/github.com/charmbracelet/huh) ([MIT](https://github.com/charmbracelet/huh/blob/v0.8.0/LICENSE))
|
||||
- [github.com/charmbracelet/lipgloss](https://pkg.go.dev/github.com/charmbracelet/lipgloss) ([MIT](https://github.com/charmbracelet/lipgloss/blob/76690c660834/LICENSE))
|
||||
- [github.com/charmbracelet/x/ansi](https://pkg.go.dev/github.com/charmbracelet/x/ansi) ([MIT](https://github.com/charmbracelet/x/blob/ansi/v0.9.3/ansi/LICENSE))
|
||||
- [github.com/charmbracelet/x/ansi](https://pkg.go.dev/github.com/charmbracelet/x/ansi) ([MIT](https://github.com/charmbracelet/x/blob/ansi/v0.10.2/ansi/LICENSE))
|
||||
- [github.com/charmbracelet/x/cellbuf](https://pkg.go.dev/github.com/charmbracelet/x/cellbuf) ([MIT](https://github.com/charmbracelet/x/blob/cellbuf/v0.0.13/cellbuf/LICENSE))
|
||||
- [github.com/charmbracelet/x/exp/slice](https://pkg.go.dev/github.com/charmbracelet/x/exp/slice) ([MIT](https://github.com/charmbracelet/x/blob/821143405392/exp/slice/LICENSE))
|
||||
- [github.com/charmbracelet/x/exp/strings](https://pkg.go.dev/github.com/charmbracelet/x/exp/strings) ([MIT](https://github.com/charmbracelet/x/blob/821143405392/exp/strings/LICENSE))
|
||||
|
|
@ -55,10 +40,9 @@ Some packages may only be included on certain architectures or operating systems
|
|||
- [github.com/cli/oauth](https://pkg.go.dev/github.com/cli/oauth) ([MIT](https://github.com/cli/oauth/blob/v1.2.1/LICENSE))
|
||||
- [github.com/cli/safeexec](https://pkg.go.dev/github.com/cli/safeexec) ([BSD-2-Clause](https://github.com/cli/safeexec/blob/v1.0.1/LICENSE))
|
||||
- [github.com/cli/shurcooL-graphql](https://pkg.go.dev/github.com/cli/shurcooL-graphql) ([MIT](https://github.com/cli/shurcooL-graphql/blob/v0.0.4/LICENSE))
|
||||
- [github.com/cncf/xds/go](https://pkg.go.dev/github.com/cncf/xds/go) ([Apache-2.0](https://github.com/cncf/xds/blob/0feb69152e9f/go/LICENSE))
|
||||
- [github.com/containerd/stargz-snapshotter/estargz](https://pkg.go.dev/github.com/containerd/stargz-snapshotter/estargz) ([Apache-2.0](https://github.com/containerd/stargz-snapshotter/blob/estargz/v0.18.1/estargz/LICENSE))
|
||||
- [github.com/cpuguy83/go-md2man/v2/md2man](https://pkg.go.dev/github.com/cpuguy83/go-md2man/v2/md2man) ([MIT](https://github.com/cpuguy83/go-md2man/blob/v2.0.7/LICENSE.md))
|
||||
- [github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer](https://pkg.go.dev/github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer) ([Apache-2.0](https://github.com/cyberphone/json-canonicalization/blob/19d51d7fe467/LICENSE))
|
||||
- [github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer](https://pkg.go.dev/github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer) ([Unknown](Unknown))
|
||||
- [github.com/davecgh/go-spew/spew](https://pkg.go.dev/github.com/davecgh/go-spew/spew) ([ISC](https://github.com/davecgh/go-spew/blob/d8f796af33cc/LICENSE))
|
||||
- [github.com/digitorus/pkcs7](https://pkg.go.dev/github.com/digitorus/pkcs7) ([MIT](https://github.com/digitorus/pkcs7/blob/3a137a874352/LICENSE))
|
||||
- [github.com/digitorus/timestamp](https://pkg.go.dev/github.com/digitorus/timestamp) ([BSD-2-Clause](https://github.com/digitorus/timestamp/blob/c45532741eea/LICENSE))
|
||||
|
|
@ -68,85 +52,72 @@ Some packages may only be included on certain architectures or operating systems
|
|||
- [github.com/docker/distribution/registry/client/auth/challenge](https://pkg.go.dev/github.com/docker/distribution/registry/client/auth/challenge) ([Apache-2.0](https://github.com/docker/distribution/blob/v2.8.3/LICENSE))
|
||||
- [github.com/docker/docker-credential-helpers](https://pkg.go.dev/github.com/docker/docker-credential-helpers) ([MIT](https://github.com/docker/docker-credential-helpers/blob/v0.9.3/LICENSE))
|
||||
- [github.com/dustin/go-humanize](https://pkg.go.dev/github.com/dustin/go-humanize) ([MIT](https://github.com/dustin/go-humanize/blob/v1.0.1/LICENSE))
|
||||
- [github.com/envoyproxy/go-control-plane/envoy](https://pkg.go.dev/github.com/envoyproxy/go-control-plane/envoy) ([Apache-2.0](https://github.com/envoyproxy/go-control-plane/blob/envoy/v1.35.0/envoy/LICENSE))
|
||||
- [github.com/envoyproxy/protoc-gen-validate/validate](https://pkg.go.dev/github.com/envoyproxy/protoc-gen-validate/validate) ([Apache-2.0](https://github.com/envoyproxy/protoc-gen-validate/blob/v1.2.1/LICENSE))
|
||||
- [github.com/fatih/color](https://pkg.go.dev/github.com/fatih/color) ([MIT](https://github.com/fatih/color/blob/v1.18.0/LICENSE.md))
|
||||
- [github.com/felixge/httpsnoop](https://pkg.go.dev/github.com/felixge/httpsnoop) ([MIT](https://github.com/felixge/httpsnoop/blob/v1.0.4/LICENSE.txt))
|
||||
- [github.com/fsnotify/fsnotify](https://pkg.go.dev/github.com/fsnotify/fsnotify) ([BSD-3-Clause](https://github.com/fsnotify/fsnotify/blob/v1.9.0/LICENSE))
|
||||
- [github.com/gabriel-vasile/mimetype](https://pkg.go.dev/github.com/gabriel-vasile/mimetype) ([MIT](https://github.com/gabriel-vasile/mimetype/blob/v1.4.11/LICENSE))
|
||||
- [github.com/gdamore/encoding](https://pkg.go.dev/github.com/gdamore/encoding) ([Apache-2.0](https://github.com/gdamore/encoding/blob/v1.0.1/LICENSE))
|
||||
- [github.com/gdamore/tcell/v2](https://pkg.go.dev/github.com/gdamore/tcell/v2) ([Apache-2.0](https://github.com/gdamore/tcell/blob/v2.13.4/LICENSE))
|
||||
- [github.com/go-chi/chi/v5](https://pkg.go.dev/github.com/go-chi/chi/v5) ([MIT](https://github.com/go-chi/chi/blob/v5.2.3/LICENSE))
|
||||
- [github.com/go-jose/go-jose/v4](https://pkg.go.dev/github.com/go-jose/go-jose/v4) ([Apache-2.0](https://github.com/go-jose/go-jose/blob/v4.1.3/LICENSE))
|
||||
- [github.com/go-jose/go-jose/v4/json](https://pkg.go.dev/github.com/go-jose/go-jose/v4/json) ([BSD-3-Clause](https://github.com/go-jose/go-jose/blob/v4.1.3/json/LICENSE))
|
||||
- [github.com/go-logr/logr](https://pkg.go.dev/github.com/go-logr/logr) ([Apache-2.0](https://github.com/go-logr/logr/blob/v1.4.3/LICENSE))
|
||||
- [github.com/go-logr/stdr](https://pkg.go.dev/github.com/go-logr/stdr) ([Apache-2.0](https://github.com/go-logr/stdr/blob/v1.2.2/LICENSE))
|
||||
- [github.com/go-openapi/analysis](https://pkg.go.dev/github.com/go-openapi/analysis) ([Apache-2.0](https://github.com/go-openapi/analysis/blob/v0.23.0/LICENSE))
|
||||
- [github.com/go-openapi/errors](https://pkg.go.dev/github.com/go-openapi/errors) ([Apache-2.0](https://github.com/go-openapi/errors/blob/v0.22.2/LICENSE))
|
||||
- [github.com/go-openapi/jsonpointer](https://pkg.go.dev/github.com/go-openapi/jsonpointer) ([Apache-2.0](https://github.com/go-openapi/jsonpointer/blob/v0.21.1/LICENSE))
|
||||
- [github.com/go-openapi/jsonreference](https://pkg.go.dev/github.com/go-openapi/jsonreference) ([Apache-2.0](https://github.com/go-openapi/jsonreference/blob/v0.21.0/LICENSE))
|
||||
- [github.com/go-openapi/loads](https://pkg.go.dev/github.com/go-openapi/loads) ([Apache-2.0](https://github.com/go-openapi/loads/blob/v0.22.0/LICENSE))
|
||||
- [github.com/go-openapi/runtime](https://pkg.go.dev/github.com/go-openapi/runtime) ([Apache-2.0](https://github.com/go-openapi/runtime/blob/v0.28.0/LICENSE))
|
||||
- [github.com/go-openapi/runtime/middleware/denco](https://pkg.go.dev/github.com/go-openapi/runtime/middleware/denco) ([MIT](https://github.com/go-openapi/runtime/blob/v0.28.0/middleware/denco/LICENSE))
|
||||
- [github.com/go-openapi/spec](https://pkg.go.dev/github.com/go-openapi/spec) ([Apache-2.0](https://github.com/go-openapi/spec/blob/v0.21.0/LICENSE))
|
||||
- [github.com/go-openapi/strfmt](https://pkg.go.dev/github.com/go-openapi/strfmt) ([Apache-2.0](https://github.com/go-openapi/strfmt/blob/v0.23.0/LICENSE))
|
||||
- [github.com/go-openapi/swag](https://pkg.go.dev/github.com/go-openapi/swag) ([Apache-2.0](https://github.com/go-openapi/swag/blob/v0.24.1/LICENSE))
|
||||
- [github.com/go-openapi/swag/cmdutils](https://pkg.go.dev/github.com/go-openapi/swag/cmdutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/cmdutils/v0.24.0/cmdutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/conv](https://pkg.go.dev/github.com/go-openapi/swag/conv) ([Apache-2.0](https://github.com/go-openapi/swag/blob/conv/v0.24.0/conv/LICENSE))
|
||||
- [github.com/go-openapi/swag/fileutils](https://pkg.go.dev/github.com/go-openapi/swag/fileutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/fileutils/v0.24.0/fileutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/jsonname](https://pkg.go.dev/github.com/go-openapi/swag/jsonname) ([Apache-2.0](https://github.com/go-openapi/swag/blob/jsonname/v0.24.0/jsonname/LICENSE))
|
||||
- [github.com/go-openapi/swag/jsonutils](https://pkg.go.dev/github.com/go-openapi/swag/jsonutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/jsonutils/v0.24.0/jsonutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/loading](https://pkg.go.dev/github.com/go-openapi/swag/loading) ([Apache-2.0](https://github.com/go-openapi/swag/blob/loading/v0.24.0/loading/LICENSE))
|
||||
- [github.com/go-openapi/swag/mangling](https://pkg.go.dev/github.com/go-openapi/swag/mangling) ([Apache-2.0](https://github.com/go-openapi/swag/blob/mangling/v0.24.0/mangling/LICENSE))
|
||||
- [github.com/go-openapi/swag/netutils](https://pkg.go.dev/github.com/go-openapi/swag/netutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/netutils/v0.24.0/netutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/stringutils](https://pkg.go.dev/github.com/go-openapi/swag/stringutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/stringutils/v0.24.0/stringutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/typeutils](https://pkg.go.dev/github.com/go-openapi/swag/typeutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/typeutils/v0.24.0/typeutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/yamlutils](https://pkg.go.dev/github.com/go-openapi/swag/yamlutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/yamlutils/v0.24.0/yamlutils/LICENSE))
|
||||
- [github.com/go-openapi/validate](https://pkg.go.dev/github.com/go-openapi/validate) ([Apache-2.0](https://github.com/go-openapi/validate/blob/v0.24.0/LICENSE))
|
||||
- [github.com/go-openapi/analysis](https://pkg.go.dev/github.com/go-openapi/analysis) ([Apache-2.0](https://github.com/go-openapi/analysis/blob/v0.24.1/LICENSE))
|
||||
- [github.com/go-openapi/errors](https://pkg.go.dev/github.com/go-openapi/errors) ([Apache-2.0](https://github.com/go-openapi/errors/blob/v0.22.4/LICENSE))
|
||||
- [github.com/go-openapi/jsonpointer](https://pkg.go.dev/github.com/go-openapi/jsonpointer) ([Apache-2.0](https://github.com/go-openapi/jsonpointer/blob/v0.22.1/LICENSE))
|
||||
- [github.com/go-openapi/jsonreference](https://pkg.go.dev/github.com/go-openapi/jsonreference) ([Apache-2.0](https://github.com/go-openapi/jsonreference/blob/v0.21.3/LICENSE))
|
||||
- [github.com/go-openapi/loads](https://pkg.go.dev/github.com/go-openapi/loads) ([Apache-2.0](https://github.com/go-openapi/loads/blob/v0.23.2/LICENSE))
|
||||
- [github.com/go-openapi/runtime](https://pkg.go.dev/github.com/go-openapi/runtime) ([Apache-2.0](https://github.com/go-openapi/runtime/blob/v0.29.2/LICENSE))
|
||||
- [github.com/go-openapi/runtime/middleware/denco](https://pkg.go.dev/github.com/go-openapi/runtime/middleware/denco) ([MIT](https://github.com/go-openapi/runtime/blob/v0.29.2/middleware/denco/LICENSE))
|
||||
- [github.com/go-openapi/spec](https://pkg.go.dev/github.com/go-openapi/spec) ([Apache-2.0](https://github.com/go-openapi/spec/blob/v0.22.1/LICENSE))
|
||||
- [github.com/go-openapi/strfmt](https://pkg.go.dev/github.com/go-openapi/strfmt) ([Apache-2.0](https://github.com/go-openapi/strfmt/blob/v0.25.0/LICENSE))
|
||||
- [github.com/go-openapi/swag](https://pkg.go.dev/github.com/go-openapi/swag) ([Apache-2.0](https://github.com/go-openapi/swag/blob/v0.25.4/LICENSE))
|
||||
- [github.com/go-openapi/swag/cmdutils](https://pkg.go.dev/github.com/go-openapi/swag/cmdutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/cmdutils/v0.25.4/cmdutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/conv](https://pkg.go.dev/github.com/go-openapi/swag/conv) ([Apache-2.0](https://github.com/go-openapi/swag/blob/conv/v0.25.4/conv/LICENSE))
|
||||
- [github.com/go-openapi/swag/fileutils](https://pkg.go.dev/github.com/go-openapi/swag/fileutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/fileutils/v0.25.4/fileutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/jsonname](https://pkg.go.dev/github.com/go-openapi/swag/jsonname) ([Apache-2.0](https://github.com/go-openapi/swag/blob/jsonname/v0.25.4/jsonname/LICENSE))
|
||||
- [github.com/go-openapi/swag/jsonutils](https://pkg.go.dev/github.com/go-openapi/swag/jsonutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/jsonutils/v0.25.4/jsonutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/loading](https://pkg.go.dev/github.com/go-openapi/swag/loading) ([Apache-2.0](https://github.com/go-openapi/swag/blob/loading/v0.25.4/loading/LICENSE))
|
||||
- [github.com/go-openapi/swag/mangling](https://pkg.go.dev/github.com/go-openapi/swag/mangling) ([Apache-2.0](https://github.com/go-openapi/swag/blob/mangling/v0.25.4/mangling/LICENSE))
|
||||
- [github.com/go-openapi/swag/netutils](https://pkg.go.dev/github.com/go-openapi/swag/netutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/netutils/v0.25.4/netutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/stringutils](https://pkg.go.dev/github.com/go-openapi/swag/stringutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/stringutils/v0.25.4/stringutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/typeutils](https://pkg.go.dev/github.com/go-openapi/swag/typeutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/typeutils/v0.25.4/typeutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/yamlutils](https://pkg.go.dev/github.com/go-openapi/swag/yamlutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/yamlutils/v0.25.4/yamlutils/LICENSE))
|
||||
- [github.com/go-openapi/validate](https://pkg.go.dev/github.com/go-openapi/validate) ([Apache-2.0](https://github.com/go-openapi/validate/blob/v0.25.1/LICENSE))
|
||||
- [github.com/go-viper/mapstructure/v2](https://pkg.go.dev/github.com/go-viper/mapstructure/v2) ([MIT](https://github.com/go-viper/mapstructure/blob/v2.4.0/LICENSE))
|
||||
- [github.com/godbus/dbus/v5](https://pkg.go.dev/github.com/godbus/dbus/v5) ([BSD-2-Clause](https://github.com/godbus/dbus/blob/v5.1.0/LICENSE))
|
||||
- [github.com/golang/groupcache/lru](https://pkg.go.dev/github.com/golang/groupcache/lru) ([Apache-2.0](https://github.com/golang/groupcache/blob/2c02b8208cf8/LICENSE))
|
||||
- [github.com/golang/snappy](https://pkg.go.dev/github.com/golang/snappy) ([BSD-3-Clause](https://github.com/golang/snappy/blob/v1.0.0/LICENSE))
|
||||
- [github.com/google/certificate-transparency-go](https://pkg.go.dev/github.com/google/certificate-transparency-go) ([Apache-2.0](https://github.com/google/certificate-transparency-go/blob/v1.3.2/LICENSE))
|
||||
- [github.com/google/go-cmp/cmp](https://pkg.go.dev/github.com/google/go-cmp/cmp) ([BSD-3-Clause](https://github.com/google/go-cmp/blob/v0.7.0/LICENSE))
|
||||
- [github.com/google/go-containerregistry](https://pkg.go.dev/github.com/google/go-containerregistry) ([Apache-2.0](https://github.com/google/go-containerregistry/blob/v0.20.7/LICENSE))
|
||||
- [github.com/google/s2a-go](https://pkg.go.dev/github.com/google/s2a-go) ([Apache-2.0](https://github.com/google/s2a-go/blob/v0.1.9/LICENSE.md))
|
||||
- [github.com/google/shlex](https://pkg.go.dev/github.com/google/shlex) ([Apache-2.0](https://github.com/google/shlex/blob/e7afc7fbc510/COPYING))
|
||||
- [github.com/google/uuid](https://pkg.go.dev/github.com/google/uuid) ([BSD-3-Clause](https://github.com/google/uuid/blob/v1.6.0/LICENSE))
|
||||
- [github.com/googleapis/enterprise-certificate-proxy/client](https://pkg.go.dev/github.com/googleapis/enterprise-certificate-proxy/client) ([Apache-2.0](https://github.com/googleapis/enterprise-certificate-proxy/blob/v0.3.6/LICENSE))
|
||||
- [github.com/googleapis/gax-go/v2](https://pkg.go.dev/github.com/googleapis/gax-go/v2) ([BSD-3-Clause](https://github.com/googleapis/gax-go/blob/v2.15.0/v2/LICENSE))
|
||||
- [github.com/gorilla/css/scanner](https://pkg.go.dev/github.com/gorilla/css/scanner) ([BSD-3-Clause](https://github.com/gorilla/css/blob/v1.0.1/LICENSE))
|
||||
- [github.com/gorilla/websocket](https://pkg.go.dev/github.com/gorilla/websocket) ([BSD-2-Clause](https://github.com/gorilla/websocket/blob/v1.5.3/LICENSE))
|
||||
- [github.com/grpc-ecosystem/grpc-gateway/v2](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/v2) ([BSD-3-Clause](https://github.com/grpc-ecosystem/grpc-gateway/blob/v2.27.2/LICENSE))
|
||||
- [github.com/grpc-ecosystem/grpc-gateway/v2](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/v2) ([BSD-3-Clause](https://github.com/grpc-ecosystem/grpc-gateway/blob/v2.27.3/LICENSE))
|
||||
- [github.com/hashicorp/go-version](https://pkg.go.dev/github.com/hashicorp/go-version) ([MPL-2.0](https://github.com/hashicorp/go-version/blob/v1.8.0/LICENSE))
|
||||
- [github.com/hashicorp/golang-lru/v2](https://pkg.go.dev/github.com/hashicorp/golang-lru/v2) ([MPL-2.0](https://github.com/hashicorp/golang-lru/blob/v2.0.7/LICENSE))
|
||||
- [github.com/hashicorp/golang-lru/v2/simplelru](https://pkg.go.dev/github.com/hashicorp/golang-lru/v2/simplelru) ([BSD-3-Clause](https://github.com/hashicorp/golang-lru/blob/v2.0.7/simplelru/LICENSE_list))
|
||||
- [github.com/henvic/httpretty](https://pkg.go.dev/github.com/henvic/httpretty) ([MIT](https://github.com/henvic/httpretty/blob/v0.1.4/LICENSE.md))
|
||||
- [github.com/huandu/xstrings](https://pkg.go.dev/github.com/huandu/xstrings) ([MIT](https://github.com/huandu/xstrings/blob/v1.5.0/LICENSE))
|
||||
- [github.com/in-toto/attestation/go/v1](https://pkg.go.dev/github.com/in-toto/attestation/go/v1) ([Apache-2.0](https://github.com/in-toto/attestation/blob/v1.1.2/LICENSE))
|
||||
- [github.com/in-toto/in-toto-golang/in_toto](https://pkg.go.dev/github.com/in-toto/in-toto-golang/in_toto) ([Apache-2.0](https://github.com/in-toto/in-toto-golang/blob/v0.9.0/LICENSE))
|
||||
- [github.com/in-toto/attestation/go/v1](https://pkg.go.dev/github.com/in-toto/attestation/go/v1) ([Unknown](Unknown))
|
||||
- [github.com/in-toto/in-toto-golang/in_toto](https://pkg.go.dev/github.com/in-toto/in-toto-golang/in_toto) ([Unknown](Unknown))
|
||||
- [github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common](https://pkg.go.dev/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common) ([Unknown](Unknown))
|
||||
- [github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.1](https://pkg.go.dev/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.1) ([Unknown](Unknown))
|
||||
- [github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2](https://pkg.go.dev/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2) ([Unknown](Unknown))
|
||||
- [github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1](https://pkg.go.dev/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1) ([Unknown](Unknown))
|
||||
- [github.com/itchyny/gojq](https://pkg.go.dev/github.com/itchyny/gojq) ([MIT](https://github.com/itchyny/gojq/blob/v0.12.17/LICENSE))
|
||||
- [github.com/itchyny/timefmt-go](https://pkg.go.dev/github.com/itchyny/timefmt-go) ([MIT](https://github.com/itchyny/timefmt-go/blob/v0.1.6/LICENSE))
|
||||
- [github.com/jedisct1/go-minisign](https://pkg.go.dev/github.com/jedisct1/go-minisign) ([MIT](https://github.com/jedisct1/go-minisign/blob/d2f9f49435c7/LICENSE))
|
||||
- [github.com/joho/godotenv](https://pkg.go.dev/github.com/joho/godotenv) ([MIT](https://github.com/joho/godotenv/blob/v1.5.1/LICENCE))
|
||||
- [github.com/josharian/intern](https://pkg.go.dev/github.com/josharian/intern) ([MIT](https://github.com/josharian/intern/blob/v1.0.0/license.md))
|
||||
- [github.com/kballard/go-shellquote](https://pkg.go.dev/github.com/kballard/go-shellquote) ([MIT](https://github.com/kballard/go-shellquote/blob/95032a82bc51/LICENSE))
|
||||
- [github.com/klauspost/compress](https://pkg.go.dev/github.com/klauspost/compress) ([MIT](https://github.com/klauspost/compress/blob/v1.18.1/LICENSE))
|
||||
- [github.com/klauspost/compress](https://pkg.go.dev/github.com/klauspost/compress) ([Apache-2.0](https://github.com/klauspost/compress/blob/v1.18.1/LICENSE))
|
||||
- [github.com/klauspost/compress](https://pkg.go.dev/github.com/klauspost/compress) ([BSD-3-Clause](https://github.com/klauspost/compress/blob/v1.18.1/LICENSE))
|
||||
- [github.com/klauspost/compress/internal/snapref](https://pkg.go.dev/github.com/klauspost/compress/internal/snapref) ([BSD-3-Clause](https://github.com/klauspost/compress/blob/v1.18.1/internal/snapref/LICENSE))
|
||||
- [github.com/klauspost/compress/zstd/internal/xxhash](https://pkg.go.dev/github.com/klauspost/compress/zstd/internal/xxhash) ([MIT](https://github.com/klauspost/compress/blob/v1.18.1/zstd/internal/xxhash/LICENSE.txt))
|
||||
- [github.com/letsencrypt/boulder](https://pkg.go.dev/github.com/letsencrypt/boulder) ([MPL-2.0](https://github.com/letsencrypt/boulder/blob/v0.20250630.0/LICENSE.txt))
|
||||
- [github.com/lucasb-eyer/go-colorful](https://pkg.go.dev/github.com/lucasb-eyer/go-colorful) ([MIT](https://github.com/lucasb-eyer/go-colorful/blob/v1.3.0/LICENSE))
|
||||
- [github.com/mailru/easyjson](https://pkg.go.dev/github.com/mailru/easyjson) ([MIT](https://github.com/mailru/easyjson/blob/v0.9.0/LICENSE))
|
||||
- [github.com/mattn/go-colorable](https://pkg.go.dev/github.com/mattn/go-colorable) ([MIT](https://github.com/mattn/go-colorable/blob/v0.1.14/LICENSE))
|
||||
- [github.com/mattn/go-isatty](https://pkg.go.dev/github.com/mattn/go-isatty) ([MIT](https://github.com/mattn/go-isatty/blob/v0.0.20/LICENSE))
|
||||
- [github.com/mattn/go-runewidth](https://pkg.go.dev/github.com/mattn/go-runewidth) ([MIT](https://github.com/mattn/go-runewidth/blob/v0.0.16/LICENSE))
|
||||
- [github.com/mattn/go-runewidth](https://pkg.go.dev/github.com/mattn/go-runewidth) ([MIT](https://github.com/mattn/go-runewidth/blob/v0.0.17/LICENSE))
|
||||
- [github.com/mgutz/ansi](https://pkg.go.dev/github.com/mgutz/ansi) ([MIT](https://github.com/mgutz/ansi/blob/d51e80ef957d/LICENSE))
|
||||
- [github.com/microcosm-cc/bluemonday](https://pkg.go.dev/github.com/microcosm-cc/bluemonday) ([BSD-3-Clause](https://github.com/microcosm-cc/bluemonday/blob/v1.0.27/LICENSE.md))
|
||||
- [github.com/microsoft/dev-tunnels/go/tunnels](https://pkg.go.dev/github.com/microsoft/dev-tunnels/go/tunnels) ([MIT](https://github.com/microsoft/dev-tunnels/blob/v0.1.19/LICENSE))
|
||||
- [github.com/mitchellh/copystructure](https://pkg.go.dev/github.com/mitchellh/copystructure) ([MIT](https://github.com/mitchellh/copystructure/blob/v1.2.0/LICENSE))
|
||||
- [github.com/mitchellh/go-homedir](https://pkg.go.dev/github.com/mitchellh/go-homedir) ([MIT](https://github.com/mitchellh/go-homedir/blob/v1.1.0/LICENSE))
|
||||
- [github.com/mitchellh/hashstructure/v2](https://pkg.go.dev/github.com/mitchellh/hashstructure/v2) ([MIT](https://github.com/mitchellh/hashstructure/blob/v2.0.2/LICENSE))
|
||||
- [github.com/mitchellh/mapstructure](https://pkg.go.dev/github.com/mitchellh/mapstructure) ([MIT](https://github.com/mitchellh/mapstructure/blob/v1.5.0/LICENSE))
|
||||
- [github.com/mitchellh/reflectwalk](https://pkg.go.dev/github.com/mitchellh/reflectwalk) ([MIT](https://github.com/mitchellh/reflectwalk/blob/v1.0.2/LICENSE))
|
||||
- [github.com/muesli/ansi](https://pkg.go.dev/github.com/muesli/ansi) ([MIT](https://github.com/muesli/ansi/blob/276c6243b2f6/LICENSE))
|
||||
- [github.com/muesli/cancelreader](https://pkg.go.dev/github.com/muesli/cancelreader) ([MIT](https://github.com/muesli/cancelreader/blob/v0.2.2/LICENSE))
|
||||
|
|
@ -157,83 +128,60 @@ Some packages may only be included on certain architectures or operating systems
|
|||
- [github.com/opencontainers/go-digest](https://pkg.go.dev/github.com/opencontainers/go-digest) ([Apache-2.0](https://github.com/opencontainers/go-digest/blob/v1.0.0/LICENSE))
|
||||
- [github.com/opencontainers/image-spec/specs-go](https://pkg.go.dev/github.com/opencontainers/image-spec/specs-go) ([Apache-2.0](https://github.com/opencontainers/image-spec/blob/v1.1.1/LICENSE))
|
||||
- [github.com/opentracing/opentracing-go](https://pkg.go.dev/github.com/opentracing/opentracing-go) ([Apache-2.0](https://github.com/opentracing/opentracing-go/blob/v1.2.0/LICENSE))
|
||||
- [github.com/pelletier/go-toml/v2](https://pkg.go.dev/github.com/pelletier/go-toml/v2) ([MIT](https://github.com/pelletier/go-toml/blob/v2.2.4/LICENSE))
|
||||
- [github.com/pkg/errors](https://pkg.go.dev/github.com/pkg/errors) ([BSD-2-Clause](https://github.com/pkg/errors/blob/v0.9.1/LICENSE))
|
||||
- [github.com/pmezard/go-difflib/difflib](https://pkg.go.dev/github.com/pmezard/go-difflib/difflib) ([BSD-3-Clause](https://github.com/pmezard/go-difflib/blob/5d4384ee4fb2/LICENSE))
|
||||
- [github.com/rivo/tview](https://pkg.go.dev/github.com/rivo/tview) ([MIT](https://github.com/rivo/tview/blob/v0.42.0/LICENSE.txt))
|
||||
- [github.com/rivo/uniseg](https://pkg.go.dev/github.com/rivo/uniseg) ([MIT](https://github.com/rivo/uniseg/blob/v0.4.7/LICENSE.txt))
|
||||
- [github.com/rodaine/table](https://pkg.go.dev/github.com/rodaine/table) ([MIT](https://github.com/rodaine/table/blob/v1.3.0/license))
|
||||
- [github.com/russross/blackfriday/v2](https://pkg.go.dev/github.com/russross/blackfriday/v2) ([BSD-2-Clause](https://github.com/russross/blackfriday/blob/v2.1.0/LICENSE.txt))
|
||||
- [github.com/sagikazarmark/locafero](https://pkg.go.dev/github.com/sagikazarmark/locafero) ([MIT](https://github.com/sagikazarmark/locafero/blob/v0.9.0/LICENSE))
|
||||
- [github.com/sassoftware/relic/lib](https://pkg.go.dev/github.com/sassoftware/relic/lib) ([Apache-2.0](https://github.com/sassoftware/relic/blob/v7.2.1/LICENSE))
|
||||
- [github.com/secure-systems-lab/go-securesystemslib](https://pkg.go.dev/github.com/secure-systems-lab/go-securesystemslib) ([MIT](https://github.com/secure-systems-lab/go-securesystemslib/blob/v0.9.1/LICENSE))
|
||||
- [github.com/shibumi/go-pathspec](https://pkg.go.dev/github.com/shibumi/go-pathspec) ([Apache-2.0](https://github.com/shibumi/go-pathspec/blob/v1.3.0/LICENSE))
|
||||
- [github.com/shopspring/decimal](https://pkg.go.dev/github.com/shopspring/decimal) ([MIT](https://github.com/shopspring/decimal/blob/v1.4.0/LICENSE))
|
||||
- [github.com/shurcooL/githubv4](https://pkg.go.dev/github.com/shurcooL/githubv4) ([MIT](https://github.com/shurcooL/githubv4/blob/48295856cce7/LICENSE))
|
||||
- [github.com/shurcooL/graphql](https://pkg.go.dev/github.com/shurcooL/graphql) ([MIT](https://github.com/shurcooL/graphql/blob/ed46e5a46466/LICENSE))
|
||||
- [github.com/sigstore/protobuf-specs/gen/pb-go](https://pkg.go.dev/github.com/sigstore/protobuf-specs/gen/pb-go) ([Apache-2.0](https://github.com/sigstore/protobuf-specs/blob/v0.5.0/LICENSE))
|
||||
- [github.com/sigstore/rekor-tiles](https://pkg.go.dev/github.com/sigstore/rekor-tiles) ([Apache-2.0](https://github.com/sigstore/rekor-tiles/blob/v0.1.11/LICENSE))
|
||||
- [github.com/sigstore/rekor/pkg](https://pkg.go.dev/github.com/sigstore/rekor/pkg) ([Apache-2.0](https://github.com/sigstore/rekor/blob/v1.4.2/LICENSE))
|
||||
- [github.com/sigstore/sigstore-go/pkg](https://pkg.go.dev/github.com/sigstore/sigstore-go/pkg) ([Apache-2.0](https://github.com/sigstore/sigstore-go/blob/v1.1.3/LICENSE))
|
||||
- [github.com/sigstore/sigstore/pkg](https://pkg.go.dev/github.com/sigstore/sigstore/pkg) ([Apache-2.0](https://github.com/sigstore/sigstore/blob/181c5d3339b3/LICENSE))
|
||||
- [github.com/sigstore/timestamp-authority/pkg/verification](https://pkg.go.dev/github.com/sigstore/timestamp-authority/pkg/verification) ([Apache-2.0](https://github.com/sigstore/timestamp-authority/blob/v1.2.9/LICENSE))
|
||||
- [github.com/sigstore/rekor-tiles/v2](https://pkg.go.dev/github.com/sigstore/rekor-tiles/v2) ([Apache-2.0](https://github.com/sigstore/rekor-tiles/blob/v2.0.1/LICENSE))
|
||||
- [github.com/sigstore/rekor/pkg](https://pkg.go.dev/github.com/sigstore/rekor/pkg) ([Apache-2.0](https://github.com/sigstore/rekor/blob/v1.4.3/LICENSE))
|
||||
- [github.com/sigstore/sigstore-go/pkg](https://pkg.go.dev/github.com/sigstore/sigstore-go/pkg) ([Apache-2.0](https://github.com/sigstore/sigstore-go/blob/v1.1.4/LICENSE))
|
||||
- [github.com/sigstore/sigstore/pkg](https://pkg.go.dev/github.com/sigstore/sigstore/pkg) ([Apache-2.0](https://github.com/sigstore/sigstore/blob/v1.10.0/LICENSE))
|
||||
- [github.com/sigstore/timestamp-authority/v2/pkg/verification](https://pkg.go.dev/github.com/sigstore/timestamp-authority/v2/pkg/verification) ([Apache-2.0](https://github.com/sigstore/timestamp-authority/blob/v2.0.3/LICENSE))
|
||||
- [github.com/sirupsen/logrus](https://pkg.go.dev/github.com/sirupsen/logrus) ([MIT](https://github.com/sirupsen/logrus/blob/v1.9.3/LICENSE))
|
||||
- [github.com/sourcegraph/conc](https://pkg.go.dev/github.com/sourcegraph/conc) ([MIT](https://github.com/sourcegraph/conc/blob/v0.3.0/LICENSE))
|
||||
- [github.com/spf13/afero](https://pkg.go.dev/github.com/spf13/afero) ([Apache-2.0](https://github.com/spf13/afero/blob/v1.14.0/LICENSE.txt))
|
||||
- [github.com/spf13/cast](https://pkg.go.dev/github.com/spf13/cast) ([MIT](https://github.com/spf13/cast/blob/v1.9.2/LICENSE))
|
||||
- [github.com/spf13/cast](https://pkg.go.dev/github.com/spf13/cast) ([MIT](https://github.com/spf13/cast/blob/v1.10.0/LICENSE))
|
||||
- [github.com/spf13/cobra](https://pkg.go.dev/github.com/spf13/cobra) ([Apache-2.0](https://github.com/spf13/cobra/blob/v1.10.2/LICENSE.txt))
|
||||
- [github.com/spf13/pflag](https://pkg.go.dev/github.com/spf13/pflag) ([BSD-3-Clause](https://github.com/spf13/pflag/blob/v1.0.10/LICENSE))
|
||||
- [github.com/spf13/viper](https://pkg.go.dev/github.com/spf13/viper) ([MIT](https://github.com/spf13/viper/blob/v1.20.1/LICENSE))
|
||||
- [github.com/spiffe/go-spiffe/v2](https://pkg.go.dev/github.com/spiffe/go-spiffe/v2) ([Apache-2.0](https://github.com/spiffe/go-spiffe/blob/v2.6.0/LICENSE))
|
||||
- [github.com/stretchr/objx](https://pkg.go.dev/github.com/stretchr/objx) ([MIT](https://github.com/stretchr/objx/blob/v0.5.2/LICENSE))
|
||||
- [github.com/stretchr/testify](https://pkg.go.dev/github.com/stretchr/testify) ([MIT](https://github.com/stretchr/testify/blob/v1.11.1/LICENSE))
|
||||
- [github.com/subosito/gotenv](https://pkg.go.dev/github.com/subosito/gotenv) ([MIT](https://github.com/subosito/gotenv/blob/v1.6.0/LICENSE))
|
||||
- [github.com/theupdateframework/go-tuf](https://pkg.go.dev/github.com/theupdateframework/go-tuf) ([BSD-3-Clause](https://github.com/theupdateframework/go-tuf/blob/v0.7.0/LICENSE))
|
||||
- [github.com/theupdateframework/go-tuf/v2/metadata](https://pkg.go.dev/github.com/theupdateframework/go-tuf/v2/metadata) ([Apache-2.0](https://github.com/theupdateframework/go-tuf/blob/v2.3.0/LICENSE))
|
||||
- [github.com/thlib/go-timezone-local/tzlocal](https://pkg.go.dev/github.com/thlib/go-timezone-local/tzlocal) ([Unlicense](https://github.com/thlib/go-timezone-local/blob/v0.0.6/LICENSE))
|
||||
- [github.com/titanous/rocacheck](https://pkg.go.dev/github.com/titanous/rocacheck) ([MIT](https://github.com/titanous/rocacheck/blob/afe73141d399/LICENSE))
|
||||
- [github.com/transparency-dev/formats](https://pkg.go.dev/github.com/transparency-dev/formats) ([Apache-2.0](https://github.com/transparency-dev/formats/blob/bb8ad4d07c26/LICENSE))
|
||||
- [github.com/transparency-dev/formats/log](https://pkg.go.dev/github.com/transparency-dev/formats/log) ([Apache-2.0](https://github.com/transparency-dev/formats/blob/404c0d5b696c/LICENSE))
|
||||
- [github.com/transparency-dev/merkle](https://pkg.go.dev/github.com/transparency-dev/merkle) ([Apache-2.0](https://github.com/transparency-dev/merkle/blob/v0.0.2/LICENSE))
|
||||
- [github.com/transparency-dev/tessera](https://pkg.go.dev/github.com/transparency-dev/tessera) ([Apache-2.0](https://github.com/transparency-dev/tessera/blob/v1.0.0-rc3/LICENSE))
|
||||
- [github.com/vbatts/tar-split/archive/tar](https://pkg.go.dev/github.com/vbatts/tar-split/archive/tar) ([BSD-3-Clause](https://github.com/vbatts/tar-split/blob/v0.12.2/LICENSE))
|
||||
- [github.com/vmihailenco/msgpack/v5](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5) ([BSD-2-Clause](https://github.com/vmihailenco/msgpack/blob/v5.4.1/LICENSE))
|
||||
- [github.com/vmihailenco/tagparser/v2](https://pkg.go.dev/github.com/vmihailenco/tagparser/v2) ([BSD-2-Clause](https://github.com/vmihailenco/tagparser/blob/v2.0.0/LICENSE))
|
||||
- [github.com/xo/terminfo](https://pkg.go.dev/github.com/xo/terminfo) ([MIT](https://github.com/xo/terminfo/blob/abceb7e1c41e/LICENSE))
|
||||
- [github.com/yuin/goldmark](https://pkg.go.dev/github.com/yuin/goldmark) ([MIT](https://github.com/yuin/goldmark/blob/v1.7.13/LICENSE))
|
||||
- [github.com/yuin/goldmark](https://pkg.go.dev/github.com/yuin/goldmark) ([MIT](https://github.com/yuin/goldmark/blob/v1.7.16/LICENSE))
|
||||
- [github.com/yuin/goldmark-emoji](https://pkg.go.dev/github.com/yuin/goldmark-emoji) ([MIT](https://github.com/yuin/goldmark-emoji/blob/v1.0.6/LICENSE))
|
||||
- [github.com/zalando/go-keyring](https://pkg.go.dev/github.com/zalando/go-keyring) ([MIT](https://github.com/zalando/go-keyring/blob/v0.2.6/LICENSE))
|
||||
- [go.mongodb.org/mongo-driver](https://pkg.go.dev/go.mongodb.org/mongo-driver) ([Apache-2.0](https://github.com/mongodb/mongo-go-driver/blob/v1.17.4/LICENSE))
|
||||
- [go.opencensus.io](https://pkg.go.dev/go.opencensus.io) ([Apache-2.0](https://github.com/census-instrumentation/opencensus-go/blob/v0.24.0/LICENSE))
|
||||
- [go.mongodb.org/mongo-driver](https://pkg.go.dev/go.mongodb.org/mongo-driver) ([Apache-2.0](https://github.com/mongodb/mongo-go-driver/blob/v1.17.6/LICENSE))
|
||||
- [go.opentelemetry.io/auto/sdk](https://pkg.go.dev/go.opentelemetry.io/auto/sdk) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go-instrumentation/blob/sdk/v1.2.1/sdk/LICENSE))
|
||||
- [go.opentelemetry.io/contrib/detectors/gcp](https://pkg.go.dev/go.opentelemetry.io/contrib/detectors/gcp) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/detectors/gcp/v1.38.0/detectors/gcp/LICENSE))
|
||||
- [go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc](https://pkg.go.dev/go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/instrumentation/google.golang.org/grpc/otelgrpc/v0.61.0/instrumentation/google.golang.org/grpc/otelgrpc/LICENSE))
|
||||
- [go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp](https://pkg.go.dev/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/instrumentation/net/http/otelhttp/v0.61.0/instrumentation/net/http/otelhttp/LICENSE))
|
||||
- [go.opentelemetry.io/otel](https://pkg.go.dev/go.opentelemetry.io/otel) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go/blob/v1.38.0/LICENSE))
|
||||
- [go.opentelemetry.io/otel](https://pkg.go.dev/go.opentelemetry.io/otel) ([BSD-3-Clause](https://github.com/open-telemetry/opentelemetry-go/blob/v1.38.0/LICENSE))
|
||||
- [go.opentelemetry.io/otel/metric](https://pkg.go.dev/go.opentelemetry.io/otel/metric) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go/blob/metric/v1.38.0/metric/LICENSE))
|
||||
- [go.opentelemetry.io/otel/sdk](https://pkg.go.dev/go.opentelemetry.io/otel/sdk) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go/blob/sdk/v1.38.0/sdk/LICENSE))
|
||||
- [go.opentelemetry.io/otel/sdk/metric](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/metric) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go/blob/sdk/metric/v1.38.0/sdk/metric/LICENSE))
|
||||
- [go.opentelemetry.io/otel/metric](https://pkg.go.dev/go.opentelemetry.io/otel/metric) ([BSD-3-Clause](https://github.com/open-telemetry/opentelemetry-go/blob/metric/v1.38.0/metric/LICENSE))
|
||||
- [go.opentelemetry.io/otel/trace](https://pkg.go.dev/go.opentelemetry.io/otel/trace) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go/blob/trace/v1.38.0/trace/LICENSE))
|
||||
- [go.uber.org/multierr](https://pkg.go.dev/go.uber.org/multierr) ([MIT](https://github.com/uber-go/multierr/blob/v1.11.0/LICENSE.txt))
|
||||
- [go.uber.org/zap](https://pkg.go.dev/go.uber.org/zap) ([MIT](https://github.com/uber-go/zap/blob/v1.27.0/LICENSE))
|
||||
- [go.opentelemetry.io/otel/trace](https://pkg.go.dev/go.opentelemetry.io/otel/trace) ([BSD-3-Clause](https://github.com/open-telemetry/opentelemetry-go/blob/trace/v1.38.0/trace/LICENSE))
|
||||
- [go.yaml.in/yaml/v3](https://pkg.go.dev/go.yaml.in/yaml/v3) ([MIT](https://github.com/yaml/go-yaml/blob/v3.0.4/LICENSE))
|
||||
- [golang.org/x/crypto](https://pkg.go.dev/golang.org/x/crypto) ([BSD-3-Clause](https://cs.opensource.google/go/x/crypto/+/v0.46.0:LICENSE))
|
||||
- [golang.org/x/exp](https://pkg.go.dev/golang.org/x/exp) ([BSD-3-Clause](https://cs.opensource.google/go/x/exp/+/b7579e27:LICENSE))
|
||||
- [golang.org/x/mod](https://pkg.go.dev/golang.org/x/mod) ([BSD-3-Clause](https://cs.opensource.google/go/x/mod/+/v0.30.0:LICENSE))
|
||||
- [golang.org/x/net](https://pkg.go.dev/golang.org/x/net) ([BSD-3-Clause](https://cs.opensource.google/go/x/net/+/v0.47.0:LICENSE))
|
||||
- [golang.org/x/oauth2](https://pkg.go.dev/golang.org/x/oauth2) ([BSD-3-Clause](https://cs.opensource.google/go/x/oauth2/+/v0.33.0:LICENSE))
|
||||
- [golang.org/x/sync](https://pkg.go.dev/golang.org/x/sync) ([BSD-3-Clause](https://cs.opensource.google/go/x/sync/+/v0.19.0:LICENSE))
|
||||
- [golang.org/x/sync/errgroup](https://pkg.go.dev/golang.org/x/sync/errgroup) ([BSD-3-Clause](https://cs.opensource.google/go/x/sync/+/v0.19.0:LICENSE))
|
||||
- [golang.org/x/sys](https://pkg.go.dev/golang.org/x/sys) ([BSD-3-Clause](https://cs.opensource.google/go/x/sys/+/v0.39.0:LICENSE))
|
||||
- [golang.org/x/term](https://pkg.go.dev/golang.org/x/term) ([BSD-3-Clause](https://cs.opensource.google/go/x/term/+/v0.38.0:LICENSE))
|
||||
- [golang.org/x/text](https://pkg.go.dev/golang.org/x/text) ([BSD-3-Clause](https://cs.opensource.google/go/x/text/+/v0.32.0:LICENSE))
|
||||
- [golang.org/x/time/rate](https://pkg.go.dev/golang.org/x/time/rate) ([BSD-3-Clause](https://cs.opensource.google/go/x/time/+/v0.12.0:LICENSE))
|
||||
- [google.golang.org/api](https://pkg.go.dev/google.golang.org/api) ([BSD-3-Clause](https://github.com/googleapis/google-api-go-client/blob/v0.248.0/LICENSE))
|
||||
- [google.golang.org/api/internal/third_party/uritemplates](https://pkg.go.dev/google.golang.org/api/internal/third_party/uritemplates) ([BSD-3-Clause](https://github.com/googleapis/google-api-go-client/blob/v0.248.0/internal/third_party/uritemplates/LICENSE))
|
||||
- [google.golang.org/genproto/googleapis/api](https://pkg.go.dev/google.golang.org/genproto/googleapis/api) ([Apache-2.0](https://github.com/googleapis/go-genproto/blob/3a174f9686a8/googleapis/api/LICENSE))
|
||||
- [google.golang.org/genproto/googleapis/rpc](https://pkg.go.dev/google.golang.org/genproto/googleapis/rpc) ([Apache-2.0](https://github.com/googleapis/go-genproto/blob/3a174f9686a8/googleapis/rpc/LICENSE))
|
||||
- [google.golang.org/genproto/googleapis/type](https://pkg.go.dev/google.golang.org/genproto/googleapis/type) ([Apache-2.0](https://github.com/googleapis/go-genproto/blob/513f23925822/LICENSE))
|
||||
- [google.golang.org/genproto/googleapis/rpc/status](https://pkg.go.dev/google.golang.org/genproto/googleapis/rpc/status) ([Apache-2.0](https://github.com/googleapis/go-genproto/blob/f26f9409b101/googleapis/rpc/LICENSE))
|
||||
- [google.golang.org/grpc](https://pkg.go.dev/google.golang.org/grpc) ([Apache-2.0](https://github.com/grpc/grpc-go/blob/v1.77.0/LICENSE))
|
||||
- [google.golang.org/protobuf](https://pkg.go.dev/google.golang.org/protobuf) ([BSD-3-Clause](https://github.com/protocolbuffers/protobuf-go/blob/v1.36.10/LICENSE))
|
||||
- [gopkg.in/yaml.v3](https://pkg.go.dev/gopkg.in/yaml.v3) ([MIT](https://github.com/go-yaml/yaml/blob/v3.0.1/LICENSE))
|
||||
- [k8s.io/klog/v2](https://pkg.go.dev/k8s.io/klog/v2) ([Apache-2.0](https://github.com/kubernetes/klog/blob/v2.130.1/LICENSE))
|
||||
|
||||
[cli/cli]: https://github.com/cli/cli
|
||||
|
|
|
|||
|
|
@ -7,23 +7,9 @@ The following open source dependencies are used to build the [cli/cli][] GitHub
|
|||
Some packages may only be included on certain architectures or operating systems.
|
||||
|
||||
|
||||
- [cel.dev/expr](https://pkg.go.dev/cel.dev/expr) ([Apache-2.0](https://github.com/google/cel-spec/blob/v0.24.0/LICENSE))
|
||||
- [cloud.google.com/go](https://pkg.go.dev/cloud.google.com/go) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/v0.121.6/LICENSE))
|
||||
- [cloud.google.com/go/auth](https://pkg.go.dev/cloud.google.com/go/auth) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/auth/v0.16.5/auth/LICENSE))
|
||||
- [cloud.google.com/go/auth/oauth2adapt](https://pkg.go.dev/cloud.google.com/go/auth/oauth2adapt) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/auth/oauth2adapt/v0.2.8/auth/oauth2adapt/LICENSE))
|
||||
- [cloud.google.com/go/compute/metadata](https://pkg.go.dev/cloud.google.com/go/compute/metadata) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/compute/metadata/v0.9.0/compute/metadata/LICENSE))
|
||||
- [cloud.google.com/go/iam](https://pkg.go.dev/cloud.google.com/go/iam) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/iam/v1.5.2/iam/LICENSE))
|
||||
- [cloud.google.com/go/longrunning](https://pkg.go.dev/cloud.google.com/go/longrunning) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/longrunning/v0.6.7/longrunning/LICENSE))
|
||||
- [cloud.google.com/go/monitoring](https://pkg.go.dev/cloud.google.com/go/monitoring) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/monitoring/v1.24.2/monitoring/LICENSE))
|
||||
- [cloud.google.com/go/spanner](https://pkg.go.dev/cloud.google.com/go/spanner) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/spanner/v1.84.1/spanner/LICENSE))
|
||||
- [cloud.google.com/go/storage](https://pkg.go.dev/cloud.google.com/go/storage) ([Apache-2.0](https://github.com/googleapis/google-cloud-go/blob/storage/v1.56.1/storage/LICENSE))
|
||||
- [dario.cat/mergo](https://pkg.go.dev/dario.cat/mergo) ([BSD-3-Clause](https://github.com/imdario/mergo/blob/v1.0.2/LICENSE))
|
||||
- [github.com/AlecAivazis/survey/v2](https://pkg.go.dev/github.com/AlecAivazis/survey/v2) ([MIT](https://github.com/AlecAivazis/survey/blob/v2.3.7/LICENSE))
|
||||
- [github.com/AlecAivazis/survey/v2/terminal](https://pkg.go.dev/github.com/AlecAivazis/survey/v2/terminal) ([MIT](https://github.com/AlecAivazis/survey/blob/v2.3.7/terminal/LICENSE.txt))
|
||||
- [github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp](https://pkg.go.dev/github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp) ([Apache-2.0](https://github.com/GoogleCloudPlatform/grpc-gcp-go/blob/grpcgcp/v1.5.3/grpcgcp/LICENSE))
|
||||
- [github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp](https://pkg.go.dev/github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp) ([Apache-2.0](https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/blob/detectors/gcp/v1.30.0/detectors/gcp/LICENSE))
|
||||
- [github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric](https://pkg.go.dev/github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric) ([Apache-2.0](https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/blob/exporter/metric/v0.53.0/exporter/metric/LICENSE))
|
||||
- [github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping](https://pkg.go.dev/github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping) ([Apache-2.0](https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/blob/internal/resourcemapping/v0.53.0/internal/resourcemapping/LICENSE))
|
||||
- [github.com/MakeNowJust/heredoc](https://pkg.go.dev/github.com/MakeNowJust/heredoc) ([MIT](https://github.com/MakeNowJust/heredoc/blob/v1.0.0/LICENSE))
|
||||
- [github.com/Masterminds/goutils](https://pkg.go.dev/github.com/Masterminds/goutils) ([Apache-2.0](https://github.com/Masterminds/goutils/blob/v1.1.1/LICENSE.txt))
|
||||
- [github.com/Masterminds/semver/v3](https://pkg.go.dev/github.com/Masterminds/semver/v3) ([MIT](https://github.com/Masterminds/semver/blob/v3.4.0/LICENSE.txt))
|
||||
|
|
@ -38,14 +24,13 @@ Some packages may only be included on certain architectures or operating systems
|
|||
- [github.com/catppuccin/go](https://pkg.go.dev/github.com/catppuccin/go) ([MIT](https://github.com/catppuccin/go/blob/v0.3.0/LICENSE))
|
||||
- [github.com/cenkalti/backoff/v4](https://pkg.go.dev/github.com/cenkalti/backoff/v4) ([MIT](https://github.com/cenkalti/backoff/blob/v4.3.0/LICENSE))
|
||||
- [github.com/cenkalti/backoff/v5](https://pkg.go.dev/github.com/cenkalti/backoff/v5) ([MIT](https://github.com/cenkalti/backoff/blob/v5.0.3/LICENSE))
|
||||
- [github.com/cespare/xxhash/v2](https://pkg.go.dev/github.com/cespare/xxhash/v2) ([MIT](https://github.com/cespare/xxhash/blob/v2.3.0/LICENSE.txt))
|
||||
- [github.com/charmbracelet/bubbles](https://pkg.go.dev/github.com/charmbracelet/bubbles) ([MIT](https://github.com/charmbracelet/bubbles/blob/23b8fd6302d7/LICENSE))
|
||||
- [github.com/charmbracelet/bubbletea](https://pkg.go.dev/github.com/charmbracelet/bubbletea) ([MIT](https://github.com/charmbracelet/bubbletea/blob/v1.3.6/LICENSE))
|
||||
- [github.com/charmbracelet/bubbletea](https://pkg.go.dev/github.com/charmbracelet/bubbletea) ([MIT](https://github.com/charmbracelet/bubbletea/blob/v1.3.10/LICENSE))
|
||||
- [github.com/charmbracelet/colorprofile](https://pkg.go.dev/github.com/charmbracelet/colorprofile) ([MIT](https://github.com/charmbracelet/colorprofile/blob/v0.3.1/LICENSE))
|
||||
- [github.com/charmbracelet/glamour](https://pkg.go.dev/github.com/charmbracelet/glamour) ([MIT](https://github.com/charmbracelet/glamour/blob/v0.10.0/LICENSE))
|
||||
- [github.com/charmbracelet/huh](https://pkg.go.dev/github.com/charmbracelet/huh) ([MIT](https://github.com/charmbracelet/huh/blob/v0.8.0/LICENSE))
|
||||
- [github.com/charmbracelet/lipgloss](https://pkg.go.dev/github.com/charmbracelet/lipgloss) ([MIT](https://github.com/charmbracelet/lipgloss/blob/76690c660834/LICENSE))
|
||||
- [github.com/charmbracelet/x/ansi](https://pkg.go.dev/github.com/charmbracelet/x/ansi) ([MIT](https://github.com/charmbracelet/x/blob/ansi/v0.9.3/ansi/LICENSE))
|
||||
- [github.com/charmbracelet/x/ansi](https://pkg.go.dev/github.com/charmbracelet/x/ansi) ([MIT](https://github.com/charmbracelet/x/blob/ansi/v0.10.2/ansi/LICENSE))
|
||||
- [github.com/charmbracelet/x/cellbuf](https://pkg.go.dev/github.com/charmbracelet/x/cellbuf) ([MIT](https://github.com/charmbracelet/x/blob/cellbuf/v0.0.13/cellbuf/LICENSE))
|
||||
- [github.com/charmbracelet/x/exp/slice](https://pkg.go.dev/github.com/charmbracelet/x/exp/slice) ([MIT](https://github.com/charmbracelet/x/blob/821143405392/exp/slice/LICENSE))
|
||||
- [github.com/charmbracelet/x/exp/strings](https://pkg.go.dev/github.com/charmbracelet/x/exp/strings) ([MIT](https://github.com/charmbracelet/x/blob/821143405392/exp/strings/LICENSE))
|
||||
|
|
@ -55,10 +40,9 @@ Some packages may only be included on certain architectures or operating systems
|
|||
- [github.com/cli/oauth](https://pkg.go.dev/github.com/cli/oauth) ([MIT](https://github.com/cli/oauth/blob/v1.2.1/LICENSE))
|
||||
- [github.com/cli/safeexec](https://pkg.go.dev/github.com/cli/safeexec) ([BSD-2-Clause](https://github.com/cli/safeexec/blob/v1.0.1/LICENSE))
|
||||
- [github.com/cli/shurcooL-graphql](https://pkg.go.dev/github.com/cli/shurcooL-graphql) ([MIT](https://github.com/cli/shurcooL-graphql/blob/v0.0.4/LICENSE))
|
||||
- [github.com/cncf/xds/go](https://pkg.go.dev/github.com/cncf/xds/go) ([Apache-2.0](https://github.com/cncf/xds/blob/0feb69152e9f/go/LICENSE))
|
||||
- [github.com/containerd/stargz-snapshotter/estargz](https://pkg.go.dev/github.com/containerd/stargz-snapshotter/estargz) ([Apache-2.0](https://github.com/containerd/stargz-snapshotter/blob/estargz/v0.18.1/estargz/LICENSE))
|
||||
- [github.com/cpuguy83/go-md2man/v2/md2man](https://pkg.go.dev/github.com/cpuguy83/go-md2man/v2/md2man) ([MIT](https://github.com/cpuguy83/go-md2man/blob/v2.0.7/LICENSE.md))
|
||||
- [github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer](https://pkg.go.dev/github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer) ([Apache-2.0](https://github.com/cyberphone/json-canonicalization/blob/19d51d7fe467/LICENSE))
|
||||
- [github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer](https://pkg.go.dev/github.com/cyberphone/json-canonicalization/go/src/webpki.org/jsoncanonicalizer) ([Unknown](Unknown))
|
||||
- [github.com/danieljoos/wincred](https://pkg.go.dev/github.com/danieljoos/wincred) ([MIT](https://github.com/danieljoos/wincred/blob/v1.2.2/LICENSE))
|
||||
- [github.com/davecgh/go-spew/spew](https://pkg.go.dev/github.com/davecgh/go-spew/spew) ([ISC](https://github.com/davecgh/go-spew/blob/d8f796af33cc/LICENSE))
|
||||
- [github.com/digitorus/pkcs7](https://pkg.go.dev/github.com/digitorus/pkcs7) ([MIT](https://github.com/digitorus/pkcs7/blob/3a137a874352/LICENSE))
|
||||
|
|
@ -69,87 +53,74 @@ Some packages may only be included on certain architectures or operating systems
|
|||
- [github.com/docker/distribution/registry/client/auth/challenge](https://pkg.go.dev/github.com/docker/distribution/registry/client/auth/challenge) ([Apache-2.0](https://github.com/docker/distribution/blob/v2.8.3/LICENSE))
|
||||
- [github.com/docker/docker-credential-helpers](https://pkg.go.dev/github.com/docker/docker-credential-helpers) ([MIT](https://github.com/docker/docker-credential-helpers/blob/v0.9.3/LICENSE))
|
||||
- [github.com/dustin/go-humanize](https://pkg.go.dev/github.com/dustin/go-humanize) ([MIT](https://github.com/dustin/go-humanize/blob/v1.0.1/LICENSE))
|
||||
- [github.com/envoyproxy/go-control-plane/envoy](https://pkg.go.dev/github.com/envoyproxy/go-control-plane/envoy) ([Apache-2.0](https://github.com/envoyproxy/go-control-plane/blob/envoy/v1.35.0/envoy/LICENSE))
|
||||
- [github.com/envoyproxy/protoc-gen-validate/validate](https://pkg.go.dev/github.com/envoyproxy/protoc-gen-validate/validate) ([Apache-2.0](https://github.com/envoyproxy/protoc-gen-validate/blob/v1.2.1/LICENSE))
|
||||
- [github.com/erikgeiser/coninput](https://pkg.go.dev/github.com/erikgeiser/coninput) ([MIT](https://github.com/erikgeiser/coninput/blob/1c3628e74d0f/LICENSE))
|
||||
- [github.com/fatih/color](https://pkg.go.dev/github.com/fatih/color) ([MIT](https://github.com/fatih/color/blob/v1.18.0/LICENSE.md))
|
||||
- [github.com/felixge/httpsnoop](https://pkg.go.dev/github.com/felixge/httpsnoop) ([MIT](https://github.com/felixge/httpsnoop/blob/v1.0.4/LICENSE.txt))
|
||||
- [github.com/fsnotify/fsnotify](https://pkg.go.dev/github.com/fsnotify/fsnotify) ([BSD-3-Clause](https://github.com/fsnotify/fsnotify/blob/v1.9.0/LICENSE))
|
||||
- [github.com/gabriel-vasile/mimetype](https://pkg.go.dev/github.com/gabriel-vasile/mimetype) ([MIT](https://github.com/gabriel-vasile/mimetype/blob/v1.4.11/LICENSE))
|
||||
- [github.com/gdamore/encoding](https://pkg.go.dev/github.com/gdamore/encoding) ([Apache-2.0](https://github.com/gdamore/encoding/blob/v1.0.1/LICENSE))
|
||||
- [github.com/gdamore/tcell/v2](https://pkg.go.dev/github.com/gdamore/tcell/v2) ([Apache-2.0](https://github.com/gdamore/tcell/blob/v2.13.4/LICENSE))
|
||||
- [github.com/go-chi/chi/v5](https://pkg.go.dev/github.com/go-chi/chi/v5) ([MIT](https://github.com/go-chi/chi/blob/v5.2.3/LICENSE))
|
||||
- [github.com/go-jose/go-jose/v4](https://pkg.go.dev/github.com/go-jose/go-jose/v4) ([Apache-2.0](https://github.com/go-jose/go-jose/blob/v4.1.3/LICENSE))
|
||||
- [github.com/go-jose/go-jose/v4/json](https://pkg.go.dev/github.com/go-jose/go-jose/v4/json) ([BSD-3-Clause](https://github.com/go-jose/go-jose/blob/v4.1.3/json/LICENSE))
|
||||
- [github.com/go-logr/logr](https://pkg.go.dev/github.com/go-logr/logr) ([Apache-2.0](https://github.com/go-logr/logr/blob/v1.4.3/LICENSE))
|
||||
- [github.com/go-logr/stdr](https://pkg.go.dev/github.com/go-logr/stdr) ([Apache-2.0](https://github.com/go-logr/stdr/blob/v1.2.2/LICENSE))
|
||||
- [github.com/go-openapi/analysis](https://pkg.go.dev/github.com/go-openapi/analysis) ([Apache-2.0](https://github.com/go-openapi/analysis/blob/v0.23.0/LICENSE))
|
||||
- [github.com/go-openapi/errors](https://pkg.go.dev/github.com/go-openapi/errors) ([Apache-2.0](https://github.com/go-openapi/errors/blob/v0.22.2/LICENSE))
|
||||
- [github.com/go-openapi/jsonpointer](https://pkg.go.dev/github.com/go-openapi/jsonpointer) ([Apache-2.0](https://github.com/go-openapi/jsonpointer/blob/v0.21.1/LICENSE))
|
||||
- [github.com/go-openapi/jsonreference](https://pkg.go.dev/github.com/go-openapi/jsonreference) ([Apache-2.0](https://github.com/go-openapi/jsonreference/blob/v0.21.0/LICENSE))
|
||||
- [github.com/go-openapi/loads](https://pkg.go.dev/github.com/go-openapi/loads) ([Apache-2.0](https://github.com/go-openapi/loads/blob/v0.22.0/LICENSE))
|
||||
- [github.com/go-openapi/runtime](https://pkg.go.dev/github.com/go-openapi/runtime) ([Apache-2.0](https://github.com/go-openapi/runtime/blob/v0.28.0/LICENSE))
|
||||
- [github.com/go-openapi/runtime/middleware/denco](https://pkg.go.dev/github.com/go-openapi/runtime/middleware/denco) ([MIT](https://github.com/go-openapi/runtime/blob/v0.28.0/middleware/denco/LICENSE))
|
||||
- [github.com/go-openapi/spec](https://pkg.go.dev/github.com/go-openapi/spec) ([Apache-2.0](https://github.com/go-openapi/spec/blob/v0.21.0/LICENSE))
|
||||
- [github.com/go-openapi/strfmt](https://pkg.go.dev/github.com/go-openapi/strfmt) ([Apache-2.0](https://github.com/go-openapi/strfmt/blob/v0.23.0/LICENSE))
|
||||
- [github.com/go-openapi/swag](https://pkg.go.dev/github.com/go-openapi/swag) ([Apache-2.0](https://github.com/go-openapi/swag/blob/v0.24.1/LICENSE))
|
||||
- [github.com/go-openapi/swag/cmdutils](https://pkg.go.dev/github.com/go-openapi/swag/cmdutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/cmdutils/v0.24.0/cmdutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/conv](https://pkg.go.dev/github.com/go-openapi/swag/conv) ([Apache-2.0](https://github.com/go-openapi/swag/blob/conv/v0.24.0/conv/LICENSE))
|
||||
- [github.com/go-openapi/swag/fileutils](https://pkg.go.dev/github.com/go-openapi/swag/fileutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/fileutils/v0.24.0/fileutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/jsonname](https://pkg.go.dev/github.com/go-openapi/swag/jsonname) ([Apache-2.0](https://github.com/go-openapi/swag/blob/jsonname/v0.24.0/jsonname/LICENSE))
|
||||
- [github.com/go-openapi/swag/jsonutils](https://pkg.go.dev/github.com/go-openapi/swag/jsonutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/jsonutils/v0.24.0/jsonutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/loading](https://pkg.go.dev/github.com/go-openapi/swag/loading) ([Apache-2.0](https://github.com/go-openapi/swag/blob/loading/v0.24.0/loading/LICENSE))
|
||||
- [github.com/go-openapi/swag/mangling](https://pkg.go.dev/github.com/go-openapi/swag/mangling) ([Apache-2.0](https://github.com/go-openapi/swag/blob/mangling/v0.24.0/mangling/LICENSE))
|
||||
- [github.com/go-openapi/swag/netutils](https://pkg.go.dev/github.com/go-openapi/swag/netutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/netutils/v0.24.0/netutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/stringutils](https://pkg.go.dev/github.com/go-openapi/swag/stringutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/stringutils/v0.24.0/stringutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/typeutils](https://pkg.go.dev/github.com/go-openapi/swag/typeutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/typeutils/v0.24.0/typeutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/yamlutils](https://pkg.go.dev/github.com/go-openapi/swag/yamlutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/yamlutils/v0.24.0/yamlutils/LICENSE))
|
||||
- [github.com/go-openapi/validate](https://pkg.go.dev/github.com/go-openapi/validate) ([Apache-2.0](https://github.com/go-openapi/validate/blob/v0.24.0/LICENSE))
|
||||
- [github.com/go-openapi/analysis](https://pkg.go.dev/github.com/go-openapi/analysis) ([Apache-2.0](https://github.com/go-openapi/analysis/blob/v0.24.1/LICENSE))
|
||||
- [github.com/go-openapi/errors](https://pkg.go.dev/github.com/go-openapi/errors) ([Apache-2.0](https://github.com/go-openapi/errors/blob/v0.22.4/LICENSE))
|
||||
- [github.com/go-openapi/jsonpointer](https://pkg.go.dev/github.com/go-openapi/jsonpointer) ([Apache-2.0](https://github.com/go-openapi/jsonpointer/blob/v0.22.1/LICENSE))
|
||||
- [github.com/go-openapi/jsonreference](https://pkg.go.dev/github.com/go-openapi/jsonreference) ([Apache-2.0](https://github.com/go-openapi/jsonreference/blob/v0.21.3/LICENSE))
|
||||
- [github.com/go-openapi/loads](https://pkg.go.dev/github.com/go-openapi/loads) ([Apache-2.0](https://github.com/go-openapi/loads/blob/v0.23.2/LICENSE))
|
||||
- [github.com/go-openapi/runtime](https://pkg.go.dev/github.com/go-openapi/runtime) ([Apache-2.0](https://github.com/go-openapi/runtime/blob/v0.29.2/LICENSE))
|
||||
- [github.com/go-openapi/runtime/middleware/denco](https://pkg.go.dev/github.com/go-openapi/runtime/middleware/denco) ([MIT](https://github.com/go-openapi/runtime/blob/v0.29.2/middleware/denco/LICENSE))
|
||||
- [github.com/go-openapi/spec](https://pkg.go.dev/github.com/go-openapi/spec) ([Apache-2.0](https://github.com/go-openapi/spec/blob/v0.22.1/LICENSE))
|
||||
- [github.com/go-openapi/strfmt](https://pkg.go.dev/github.com/go-openapi/strfmt) ([Apache-2.0](https://github.com/go-openapi/strfmt/blob/v0.25.0/LICENSE))
|
||||
- [github.com/go-openapi/swag](https://pkg.go.dev/github.com/go-openapi/swag) ([Apache-2.0](https://github.com/go-openapi/swag/blob/v0.25.4/LICENSE))
|
||||
- [github.com/go-openapi/swag/cmdutils](https://pkg.go.dev/github.com/go-openapi/swag/cmdutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/cmdutils/v0.25.4/cmdutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/conv](https://pkg.go.dev/github.com/go-openapi/swag/conv) ([Apache-2.0](https://github.com/go-openapi/swag/blob/conv/v0.25.4/conv/LICENSE))
|
||||
- [github.com/go-openapi/swag/fileutils](https://pkg.go.dev/github.com/go-openapi/swag/fileutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/fileutils/v0.25.4/fileutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/jsonname](https://pkg.go.dev/github.com/go-openapi/swag/jsonname) ([Apache-2.0](https://github.com/go-openapi/swag/blob/jsonname/v0.25.4/jsonname/LICENSE))
|
||||
- [github.com/go-openapi/swag/jsonutils](https://pkg.go.dev/github.com/go-openapi/swag/jsonutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/jsonutils/v0.25.4/jsonutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/loading](https://pkg.go.dev/github.com/go-openapi/swag/loading) ([Apache-2.0](https://github.com/go-openapi/swag/blob/loading/v0.25.4/loading/LICENSE))
|
||||
- [github.com/go-openapi/swag/mangling](https://pkg.go.dev/github.com/go-openapi/swag/mangling) ([Apache-2.0](https://github.com/go-openapi/swag/blob/mangling/v0.25.4/mangling/LICENSE))
|
||||
- [github.com/go-openapi/swag/netutils](https://pkg.go.dev/github.com/go-openapi/swag/netutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/netutils/v0.25.4/netutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/stringutils](https://pkg.go.dev/github.com/go-openapi/swag/stringutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/stringutils/v0.25.4/stringutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/typeutils](https://pkg.go.dev/github.com/go-openapi/swag/typeutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/typeutils/v0.25.4/typeutils/LICENSE))
|
||||
- [github.com/go-openapi/swag/yamlutils](https://pkg.go.dev/github.com/go-openapi/swag/yamlutils) ([Apache-2.0](https://github.com/go-openapi/swag/blob/yamlutils/v0.25.4/yamlutils/LICENSE))
|
||||
- [github.com/go-openapi/validate](https://pkg.go.dev/github.com/go-openapi/validate) ([Apache-2.0](https://github.com/go-openapi/validate/blob/v0.25.1/LICENSE))
|
||||
- [github.com/go-viper/mapstructure/v2](https://pkg.go.dev/github.com/go-viper/mapstructure/v2) ([MIT](https://github.com/go-viper/mapstructure/blob/v2.4.0/LICENSE))
|
||||
- [github.com/golang/groupcache/lru](https://pkg.go.dev/github.com/golang/groupcache/lru) ([Apache-2.0](https://github.com/golang/groupcache/blob/2c02b8208cf8/LICENSE))
|
||||
- [github.com/golang/snappy](https://pkg.go.dev/github.com/golang/snappy) ([BSD-3-Clause](https://github.com/golang/snappy/blob/v1.0.0/LICENSE))
|
||||
- [github.com/google/certificate-transparency-go](https://pkg.go.dev/github.com/google/certificate-transparency-go) ([Apache-2.0](https://github.com/google/certificate-transparency-go/blob/v1.3.2/LICENSE))
|
||||
- [github.com/google/go-cmp/cmp](https://pkg.go.dev/github.com/google/go-cmp/cmp) ([BSD-3-Clause](https://github.com/google/go-cmp/blob/v0.7.0/LICENSE))
|
||||
- [github.com/google/go-containerregistry](https://pkg.go.dev/github.com/google/go-containerregistry) ([Apache-2.0](https://github.com/google/go-containerregistry/blob/v0.20.7/LICENSE))
|
||||
- [github.com/google/s2a-go](https://pkg.go.dev/github.com/google/s2a-go) ([Apache-2.0](https://github.com/google/s2a-go/blob/v0.1.9/LICENSE.md))
|
||||
- [github.com/google/shlex](https://pkg.go.dev/github.com/google/shlex) ([Apache-2.0](https://github.com/google/shlex/blob/e7afc7fbc510/COPYING))
|
||||
- [github.com/google/uuid](https://pkg.go.dev/github.com/google/uuid) ([BSD-3-Clause](https://github.com/google/uuid/blob/v1.6.0/LICENSE))
|
||||
- [github.com/googleapis/enterprise-certificate-proxy/client](https://pkg.go.dev/github.com/googleapis/enterprise-certificate-proxy/client) ([Apache-2.0](https://github.com/googleapis/enterprise-certificate-proxy/blob/v0.3.6/LICENSE))
|
||||
- [github.com/googleapis/gax-go/v2](https://pkg.go.dev/github.com/googleapis/gax-go/v2) ([BSD-3-Clause](https://github.com/googleapis/gax-go/blob/v2.15.0/v2/LICENSE))
|
||||
- [github.com/gorilla/css/scanner](https://pkg.go.dev/github.com/gorilla/css/scanner) ([BSD-3-Clause](https://github.com/gorilla/css/blob/v1.0.1/LICENSE))
|
||||
- [github.com/gorilla/websocket](https://pkg.go.dev/github.com/gorilla/websocket) ([BSD-2-Clause](https://github.com/gorilla/websocket/blob/v1.5.3/LICENSE))
|
||||
- [github.com/grpc-ecosystem/grpc-gateway/v2](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/v2) ([BSD-3-Clause](https://github.com/grpc-ecosystem/grpc-gateway/blob/v2.27.2/LICENSE))
|
||||
- [github.com/grpc-ecosystem/grpc-gateway/v2](https://pkg.go.dev/github.com/grpc-ecosystem/grpc-gateway/v2) ([BSD-3-Clause](https://github.com/grpc-ecosystem/grpc-gateway/blob/v2.27.3/LICENSE))
|
||||
- [github.com/hashicorp/go-version](https://pkg.go.dev/github.com/hashicorp/go-version) ([MPL-2.0](https://github.com/hashicorp/go-version/blob/v1.8.0/LICENSE))
|
||||
- [github.com/hashicorp/golang-lru/v2](https://pkg.go.dev/github.com/hashicorp/golang-lru/v2) ([MPL-2.0](https://github.com/hashicorp/golang-lru/blob/v2.0.7/LICENSE))
|
||||
- [github.com/hashicorp/golang-lru/v2/simplelru](https://pkg.go.dev/github.com/hashicorp/golang-lru/v2/simplelru) ([BSD-3-Clause](https://github.com/hashicorp/golang-lru/blob/v2.0.7/simplelru/LICENSE_list))
|
||||
- [github.com/henvic/httpretty](https://pkg.go.dev/github.com/henvic/httpretty) ([MIT](https://github.com/henvic/httpretty/blob/v0.1.4/LICENSE.md))
|
||||
- [github.com/huandu/xstrings](https://pkg.go.dev/github.com/huandu/xstrings) ([MIT](https://github.com/huandu/xstrings/blob/v1.5.0/LICENSE))
|
||||
- [github.com/in-toto/attestation/go/v1](https://pkg.go.dev/github.com/in-toto/attestation/go/v1) ([Apache-2.0](https://github.com/in-toto/attestation/blob/v1.1.2/LICENSE))
|
||||
- [github.com/in-toto/in-toto-golang/in_toto](https://pkg.go.dev/github.com/in-toto/in-toto-golang/in_toto) ([Apache-2.0](https://github.com/in-toto/in-toto-golang/blob/v0.9.0/LICENSE))
|
||||
- [github.com/in-toto/attestation/go/v1](https://pkg.go.dev/github.com/in-toto/attestation/go/v1) ([Unknown](Unknown))
|
||||
- [github.com/in-toto/in-toto-golang/in_toto](https://pkg.go.dev/github.com/in-toto/in-toto-golang/in_toto) ([Unknown](Unknown))
|
||||
- [github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common](https://pkg.go.dev/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common) ([Unknown](Unknown))
|
||||
- [github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.1](https://pkg.go.dev/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.1) ([Unknown](Unknown))
|
||||
- [github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2](https://pkg.go.dev/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2) ([Unknown](Unknown))
|
||||
- [github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1](https://pkg.go.dev/github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1) ([Unknown](Unknown))
|
||||
- [github.com/inconshreveable/mousetrap](https://pkg.go.dev/github.com/inconshreveable/mousetrap) ([Apache-2.0](https://github.com/inconshreveable/mousetrap/blob/v1.1.0/LICENSE))
|
||||
- [github.com/itchyny/gojq](https://pkg.go.dev/github.com/itchyny/gojq) ([MIT](https://github.com/itchyny/gojq/blob/v0.12.17/LICENSE))
|
||||
- [github.com/itchyny/timefmt-go](https://pkg.go.dev/github.com/itchyny/timefmt-go) ([MIT](https://github.com/itchyny/timefmt-go/blob/v0.1.6/LICENSE))
|
||||
- [github.com/jedisct1/go-minisign](https://pkg.go.dev/github.com/jedisct1/go-minisign) ([MIT](https://github.com/jedisct1/go-minisign/blob/d2f9f49435c7/LICENSE))
|
||||
- [github.com/joho/godotenv](https://pkg.go.dev/github.com/joho/godotenv) ([MIT](https://github.com/joho/godotenv/blob/v1.5.1/LICENCE))
|
||||
- [github.com/josharian/intern](https://pkg.go.dev/github.com/josharian/intern) ([MIT](https://github.com/josharian/intern/blob/v1.0.0/license.md))
|
||||
- [github.com/kballard/go-shellquote](https://pkg.go.dev/github.com/kballard/go-shellquote) ([MIT](https://github.com/kballard/go-shellquote/blob/95032a82bc51/LICENSE))
|
||||
- [github.com/klauspost/compress](https://pkg.go.dev/github.com/klauspost/compress) ([MIT](https://github.com/klauspost/compress/blob/v1.18.1/LICENSE))
|
||||
- [github.com/klauspost/compress](https://pkg.go.dev/github.com/klauspost/compress) ([Apache-2.0](https://github.com/klauspost/compress/blob/v1.18.1/LICENSE))
|
||||
- [github.com/klauspost/compress](https://pkg.go.dev/github.com/klauspost/compress) ([BSD-3-Clause](https://github.com/klauspost/compress/blob/v1.18.1/LICENSE))
|
||||
- [github.com/klauspost/compress/internal/snapref](https://pkg.go.dev/github.com/klauspost/compress/internal/snapref) ([BSD-3-Clause](https://github.com/klauspost/compress/blob/v1.18.1/internal/snapref/LICENSE))
|
||||
- [github.com/klauspost/compress/zstd/internal/xxhash](https://pkg.go.dev/github.com/klauspost/compress/zstd/internal/xxhash) ([MIT](https://github.com/klauspost/compress/blob/v1.18.1/zstd/internal/xxhash/LICENSE.txt))
|
||||
- [github.com/letsencrypt/boulder](https://pkg.go.dev/github.com/letsencrypt/boulder) ([MPL-2.0](https://github.com/letsencrypt/boulder/blob/v0.20250630.0/LICENSE.txt))
|
||||
- [github.com/lucasb-eyer/go-colorful](https://pkg.go.dev/github.com/lucasb-eyer/go-colorful) ([MIT](https://github.com/lucasb-eyer/go-colorful/blob/v1.3.0/LICENSE))
|
||||
- [github.com/mailru/easyjson](https://pkg.go.dev/github.com/mailru/easyjson) ([MIT](https://github.com/mailru/easyjson/blob/v0.9.0/LICENSE))
|
||||
- [github.com/mattn/go-colorable](https://pkg.go.dev/github.com/mattn/go-colorable) ([MIT](https://github.com/mattn/go-colorable/blob/v0.1.14/LICENSE))
|
||||
- [github.com/mattn/go-isatty](https://pkg.go.dev/github.com/mattn/go-isatty) ([MIT](https://github.com/mattn/go-isatty/blob/v0.0.20/LICENSE))
|
||||
- [github.com/mattn/go-localereader](https://pkg.go.dev/github.com/mattn/go-localereader) ([Unknown](Unknown))
|
||||
- [github.com/mattn/go-runewidth](https://pkg.go.dev/github.com/mattn/go-runewidth) ([MIT](https://github.com/mattn/go-runewidth/blob/v0.0.16/LICENSE))
|
||||
- [github.com/mattn/go-runewidth](https://pkg.go.dev/github.com/mattn/go-runewidth) ([MIT](https://github.com/mattn/go-runewidth/blob/v0.0.17/LICENSE))
|
||||
- [github.com/mgutz/ansi](https://pkg.go.dev/github.com/mgutz/ansi) ([MIT](https://github.com/mgutz/ansi/blob/d51e80ef957d/LICENSE))
|
||||
- [github.com/microcosm-cc/bluemonday](https://pkg.go.dev/github.com/microcosm-cc/bluemonday) ([BSD-3-Clause](https://github.com/microcosm-cc/bluemonday/blob/v1.0.27/LICENSE.md))
|
||||
- [github.com/microsoft/dev-tunnels/go/tunnels](https://pkg.go.dev/github.com/microsoft/dev-tunnels/go/tunnels) ([MIT](https://github.com/microsoft/dev-tunnels/blob/v0.1.19/LICENSE))
|
||||
- [github.com/mitchellh/copystructure](https://pkg.go.dev/github.com/mitchellh/copystructure) ([MIT](https://github.com/mitchellh/copystructure/blob/v1.2.0/LICENSE))
|
||||
- [github.com/mitchellh/go-homedir](https://pkg.go.dev/github.com/mitchellh/go-homedir) ([MIT](https://github.com/mitchellh/go-homedir/blob/v1.1.0/LICENSE))
|
||||
- [github.com/mitchellh/hashstructure/v2](https://pkg.go.dev/github.com/mitchellh/hashstructure/v2) ([MIT](https://github.com/mitchellh/hashstructure/blob/v2.0.2/LICENSE))
|
||||
- [github.com/mitchellh/mapstructure](https://pkg.go.dev/github.com/mitchellh/mapstructure) ([MIT](https://github.com/mitchellh/mapstructure/blob/v1.5.0/LICENSE))
|
||||
- [github.com/mitchellh/reflectwalk](https://pkg.go.dev/github.com/mitchellh/reflectwalk) ([MIT](https://github.com/mitchellh/reflectwalk/blob/v1.0.2/LICENSE))
|
||||
- [github.com/muesli/ansi](https://pkg.go.dev/github.com/muesli/ansi) ([MIT](https://github.com/muesli/ansi/blob/276c6243b2f6/LICENSE))
|
||||
- [github.com/muesli/cancelreader](https://pkg.go.dev/github.com/muesli/cancelreader) ([MIT](https://github.com/muesli/cancelreader/blob/v0.2.2/LICENSE))
|
||||
|
|
@ -160,83 +131,60 @@ Some packages may only be included on certain architectures or operating systems
|
|||
- [github.com/opencontainers/go-digest](https://pkg.go.dev/github.com/opencontainers/go-digest) ([Apache-2.0](https://github.com/opencontainers/go-digest/blob/v1.0.0/LICENSE))
|
||||
- [github.com/opencontainers/image-spec/specs-go](https://pkg.go.dev/github.com/opencontainers/image-spec/specs-go) ([Apache-2.0](https://github.com/opencontainers/image-spec/blob/v1.1.1/LICENSE))
|
||||
- [github.com/opentracing/opentracing-go](https://pkg.go.dev/github.com/opentracing/opentracing-go) ([Apache-2.0](https://github.com/opentracing/opentracing-go/blob/v1.2.0/LICENSE))
|
||||
- [github.com/pelletier/go-toml/v2](https://pkg.go.dev/github.com/pelletier/go-toml/v2) ([MIT](https://github.com/pelletier/go-toml/blob/v2.2.4/LICENSE))
|
||||
- [github.com/pkg/errors](https://pkg.go.dev/github.com/pkg/errors) ([BSD-2-Clause](https://github.com/pkg/errors/blob/v0.9.1/LICENSE))
|
||||
- [github.com/pmezard/go-difflib/difflib](https://pkg.go.dev/github.com/pmezard/go-difflib/difflib) ([BSD-3-Clause](https://github.com/pmezard/go-difflib/blob/5d4384ee4fb2/LICENSE))
|
||||
- [github.com/rivo/tview](https://pkg.go.dev/github.com/rivo/tview) ([MIT](https://github.com/rivo/tview/blob/v0.42.0/LICENSE.txt))
|
||||
- [github.com/rivo/uniseg](https://pkg.go.dev/github.com/rivo/uniseg) ([MIT](https://github.com/rivo/uniseg/blob/v0.4.7/LICENSE.txt))
|
||||
- [github.com/rodaine/table](https://pkg.go.dev/github.com/rodaine/table) ([MIT](https://github.com/rodaine/table/blob/v1.3.0/license))
|
||||
- [github.com/russross/blackfriday/v2](https://pkg.go.dev/github.com/russross/blackfriday/v2) ([BSD-2-Clause](https://github.com/russross/blackfriday/blob/v2.1.0/LICENSE.txt))
|
||||
- [github.com/sagikazarmark/locafero](https://pkg.go.dev/github.com/sagikazarmark/locafero) ([MIT](https://github.com/sagikazarmark/locafero/blob/v0.9.0/LICENSE))
|
||||
- [github.com/sassoftware/relic/lib](https://pkg.go.dev/github.com/sassoftware/relic/lib) ([Apache-2.0](https://github.com/sassoftware/relic/blob/v7.2.1/LICENSE))
|
||||
- [github.com/secure-systems-lab/go-securesystemslib](https://pkg.go.dev/github.com/secure-systems-lab/go-securesystemslib) ([MIT](https://github.com/secure-systems-lab/go-securesystemslib/blob/v0.9.1/LICENSE))
|
||||
- [github.com/shibumi/go-pathspec](https://pkg.go.dev/github.com/shibumi/go-pathspec) ([Apache-2.0](https://github.com/shibumi/go-pathspec/blob/v1.3.0/LICENSE))
|
||||
- [github.com/shopspring/decimal](https://pkg.go.dev/github.com/shopspring/decimal) ([MIT](https://github.com/shopspring/decimal/blob/v1.4.0/LICENSE))
|
||||
- [github.com/shurcooL/githubv4](https://pkg.go.dev/github.com/shurcooL/githubv4) ([MIT](https://github.com/shurcooL/githubv4/blob/48295856cce7/LICENSE))
|
||||
- [github.com/shurcooL/graphql](https://pkg.go.dev/github.com/shurcooL/graphql) ([MIT](https://github.com/shurcooL/graphql/blob/ed46e5a46466/LICENSE))
|
||||
- [github.com/sigstore/protobuf-specs/gen/pb-go](https://pkg.go.dev/github.com/sigstore/protobuf-specs/gen/pb-go) ([Apache-2.0](https://github.com/sigstore/protobuf-specs/blob/v0.5.0/LICENSE))
|
||||
- [github.com/sigstore/rekor-tiles](https://pkg.go.dev/github.com/sigstore/rekor-tiles) ([Apache-2.0](https://github.com/sigstore/rekor-tiles/blob/v0.1.11/LICENSE))
|
||||
- [github.com/sigstore/rekor/pkg](https://pkg.go.dev/github.com/sigstore/rekor/pkg) ([Apache-2.0](https://github.com/sigstore/rekor/blob/v1.4.2/LICENSE))
|
||||
- [github.com/sigstore/sigstore-go/pkg](https://pkg.go.dev/github.com/sigstore/sigstore-go/pkg) ([Apache-2.0](https://github.com/sigstore/sigstore-go/blob/v1.1.3/LICENSE))
|
||||
- [github.com/sigstore/sigstore/pkg](https://pkg.go.dev/github.com/sigstore/sigstore/pkg) ([Apache-2.0](https://github.com/sigstore/sigstore/blob/181c5d3339b3/LICENSE))
|
||||
- [github.com/sigstore/timestamp-authority/pkg/verification](https://pkg.go.dev/github.com/sigstore/timestamp-authority/pkg/verification) ([Apache-2.0](https://github.com/sigstore/timestamp-authority/blob/v1.2.9/LICENSE))
|
||||
- [github.com/sigstore/rekor-tiles/v2](https://pkg.go.dev/github.com/sigstore/rekor-tiles/v2) ([Apache-2.0](https://github.com/sigstore/rekor-tiles/blob/v2.0.1/LICENSE))
|
||||
- [github.com/sigstore/rekor/pkg](https://pkg.go.dev/github.com/sigstore/rekor/pkg) ([Apache-2.0](https://github.com/sigstore/rekor/blob/v1.4.3/LICENSE))
|
||||
- [github.com/sigstore/sigstore-go/pkg](https://pkg.go.dev/github.com/sigstore/sigstore-go/pkg) ([Apache-2.0](https://github.com/sigstore/sigstore-go/blob/v1.1.4/LICENSE))
|
||||
- [github.com/sigstore/sigstore/pkg](https://pkg.go.dev/github.com/sigstore/sigstore/pkg) ([Apache-2.0](https://github.com/sigstore/sigstore/blob/v1.10.0/LICENSE))
|
||||
- [github.com/sigstore/timestamp-authority/v2/pkg/verification](https://pkg.go.dev/github.com/sigstore/timestamp-authority/v2/pkg/verification) ([Apache-2.0](https://github.com/sigstore/timestamp-authority/blob/v2.0.3/LICENSE))
|
||||
- [github.com/sirupsen/logrus](https://pkg.go.dev/github.com/sirupsen/logrus) ([MIT](https://github.com/sirupsen/logrus/blob/v1.9.3/LICENSE))
|
||||
- [github.com/sourcegraph/conc](https://pkg.go.dev/github.com/sourcegraph/conc) ([MIT](https://github.com/sourcegraph/conc/blob/v0.3.0/LICENSE))
|
||||
- [github.com/spf13/afero](https://pkg.go.dev/github.com/spf13/afero) ([Apache-2.0](https://github.com/spf13/afero/blob/v1.14.0/LICENSE.txt))
|
||||
- [github.com/spf13/cast](https://pkg.go.dev/github.com/spf13/cast) ([MIT](https://github.com/spf13/cast/blob/v1.9.2/LICENSE))
|
||||
- [github.com/spf13/cast](https://pkg.go.dev/github.com/spf13/cast) ([MIT](https://github.com/spf13/cast/blob/v1.10.0/LICENSE))
|
||||
- [github.com/spf13/cobra](https://pkg.go.dev/github.com/spf13/cobra) ([Apache-2.0](https://github.com/spf13/cobra/blob/v1.10.2/LICENSE.txt))
|
||||
- [github.com/spf13/pflag](https://pkg.go.dev/github.com/spf13/pflag) ([BSD-3-Clause](https://github.com/spf13/pflag/blob/v1.0.10/LICENSE))
|
||||
- [github.com/spf13/viper](https://pkg.go.dev/github.com/spf13/viper) ([MIT](https://github.com/spf13/viper/blob/v1.20.1/LICENSE))
|
||||
- [github.com/spiffe/go-spiffe/v2](https://pkg.go.dev/github.com/spiffe/go-spiffe/v2) ([Apache-2.0](https://github.com/spiffe/go-spiffe/blob/v2.6.0/LICENSE))
|
||||
- [github.com/stretchr/objx](https://pkg.go.dev/github.com/stretchr/objx) ([MIT](https://github.com/stretchr/objx/blob/v0.5.2/LICENSE))
|
||||
- [github.com/stretchr/testify](https://pkg.go.dev/github.com/stretchr/testify) ([MIT](https://github.com/stretchr/testify/blob/v1.11.1/LICENSE))
|
||||
- [github.com/subosito/gotenv](https://pkg.go.dev/github.com/subosito/gotenv) ([MIT](https://github.com/subosito/gotenv/blob/v1.6.0/LICENSE))
|
||||
- [github.com/theupdateframework/go-tuf](https://pkg.go.dev/github.com/theupdateframework/go-tuf) ([BSD-3-Clause](https://github.com/theupdateframework/go-tuf/blob/v0.7.0/LICENSE))
|
||||
- [github.com/theupdateframework/go-tuf/v2/metadata](https://pkg.go.dev/github.com/theupdateframework/go-tuf/v2/metadata) ([Apache-2.0](https://github.com/theupdateframework/go-tuf/blob/v2.3.0/LICENSE))
|
||||
- [github.com/thlib/go-timezone-local/tzlocal](https://pkg.go.dev/github.com/thlib/go-timezone-local/tzlocal) ([Unlicense](https://github.com/thlib/go-timezone-local/blob/v0.0.6/LICENSE))
|
||||
- [github.com/titanous/rocacheck](https://pkg.go.dev/github.com/titanous/rocacheck) ([MIT](https://github.com/titanous/rocacheck/blob/afe73141d399/LICENSE))
|
||||
- [github.com/transparency-dev/formats](https://pkg.go.dev/github.com/transparency-dev/formats) ([Apache-2.0](https://github.com/transparency-dev/formats/blob/bb8ad4d07c26/LICENSE))
|
||||
- [github.com/transparency-dev/formats/log](https://pkg.go.dev/github.com/transparency-dev/formats/log) ([Apache-2.0](https://github.com/transparency-dev/formats/blob/404c0d5b696c/LICENSE))
|
||||
- [github.com/transparency-dev/merkle](https://pkg.go.dev/github.com/transparency-dev/merkle) ([Apache-2.0](https://github.com/transparency-dev/merkle/blob/v0.0.2/LICENSE))
|
||||
- [github.com/transparency-dev/tessera](https://pkg.go.dev/github.com/transparency-dev/tessera) ([Apache-2.0](https://github.com/transparency-dev/tessera/blob/v1.0.0-rc3/LICENSE))
|
||||
- [github.com/vbatts/tar-split/archive/tar](https://pkg.go.dev/github.com/vbatts/tar-split/archive/tar) ([BSD-3-Clause](https://github.com/vbatts/tar-split/blob/v0.12.2/LICENSE))
|
||||
- [github.com/vmihailenco/msgpack/v5](https://pkg.go.dev/github.com/vmihailenco/msgpack/v5) ([BSD-2-Clause](https://github.com/vmihailenco/msgpack/blob/v5.4.1/LICENSE))
|
||||
- [github.com/vmihailenco/tagparser/v2](https://pkg.go.dev/github.com/vmihailenco/tagparser/v2) ([BSD-2-Clause](https://github.com/vmihailenco/tagparser/blob/v2.0.0/LICENSE))
|
||||
- [github.com/xo/terminfo](https://pkg.go.dev/github.com/xo/terminfo) ([MIT](https://github.com/xo/terminfo/blob/abceb7e1c41e/LICENSE))
|
||||
- [github.com/yuin/goldmark](https://pkg.go.dev/github.com/yuin/goldmark) ([MIT](https://github.com/yuin/goldmark/blob/v1.7.13/LICENSE))
|
||||
- [github.com/yuin/goldmark](https://pkg.go.dev/github.com/yuin/goldmark) ([MIT](https://github.com/yuin/goldmark/blob/v1.7.16/LICENSE))
|
||||
- [github.com/yuin/goldmark-emoji](https://pkg.go.dev/github.com/yuin/goldmark-emoji) ([MIT](https://github.com/yuin/goldmark-emoji/blob/v1.0.6/LICENSE))
|
||||
- [github.com/zalando/go-keyring](https://pkg.go.dev/github.com/zalando/go-keyring) ([MIT](https://github.com/zalando/go-keyring/blob/v0.2.6/LICENSE))
|
||||
- [go.mongodb.org/mongo-driver](https://pkg.go.dev/go.mongodb.org/mongo-driver) ([Apache-2.0](https://github.com/mongodb/mongo-go-driver/blob/v1.17.4/LICENSE))
|
||||
- [go.opencensus.io](https://pkg.go.dev/go.opencensus.io) ([Apache-2.0](https://github.com/census-instrumentation/opencensus-go/blob/v0.24.0/LICENSE))
|
||||
- [go.mongodb.org/mongo-driver](https://pkg.go.dev/go.mongodb.org/mongo-driver) ([Apache-2.0](https://github.com/mongodb/mongo-go-driver/blob/v1.17.6/LICENSE))
|
||||
- [go.opentelemetry.io/auto/sdk](https://pkg.go.dev/go.opentelemetry.io/auto/sdk) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go-instrumentation/blob/sdk/v1.2.1/sdk/LICENSE))
|
||||
- [go.opentelemetry.io/contrib/detectors/gcp](https://pkg.go.dev/go.opentelemetry.io/contrib/detectors/gcp) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/detectors/gcp/v1.38.0/detectors/gcp/LICENSE))
|
||||
- [go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc](https://pkg.go.dev/go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/instrumentation/google.golang.org/grpc/otelgrpc/v0.61.0/instrumentation/google.golang.org/grpc/otelgrpc/LICENSE))
|
||||
- [go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp](https://pkg.go.dev/go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go-contrib/blob/instrumentation/net/http/otelhttp/v0.61.0/instrumentation/net/http/otelhttp/LICENSE))
|
||||
- [go.opentelemetry.io/otel](https://pkg.go.dev/go.opentelemetry.io/otel) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go/blob/v1.38.0/LICENSE))
|
||||
- [go.opentelemetry.io/otel](https://pkg.go.dev/go.opentelemetry.io/otel) ([BSD-3-Clause](https://github.com/open-telemetry/opentelemetry-go/blob/v1.38.0/LICENSE))
|
||||
- [go.opentelemetry.io/otel/metric](https://pkg.go.dev/go.opentelemetry.io/otel/metric) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go/blob/metric/v1.38.0/metric/LICENSE))
|
||||
- [go.opentelemetry.io/otel/sdk](https://pkg.go.dev/go.opentelemetry.io/otel/sdk) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go/blob/sdk/v1.38.0/sdk/LICENSE))
|
||||
- [go.opentelemetry.io/otel/sdk/metric](https://pkg.go.dev/go.opentelemetry.io/otel/sdk/metric) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go/blob/sdk/metric/v1.38.0/sdk/metric/LICENSE))
|
||||
- [go.opentelemetry.io/otel/metric](https://pkg.go.dev/go.opentelemetry.io/otel/metric) ([BSD-3-Clause](https://github.com/open-telemetry/opentelemetry-go/blob/metric/v1.38.0/metric/LICENSE))
|
||||
- [go.opentelemetry.io/otel/trace](https://pkg.go.dev/go.opentelemetry.io/otel/trace) ([Apache-2.0](https://github.com/open-telemetry/opentelemetry-go/blob/trace/v1.38.0/trace/LICENSE))
|
||||
- [go.uber.org/multierr](https://pkg.go.dev/go.uber.org/multierr) ([MIT](https://github.com/uber-go/multierr/blob/v1.11.0/LICENSE.txt))
|
||||
- [go.uber.org/zap](https://pkg.go.dev/go.uber.org/zap) ([MIT](https://github.com/uber-go/zap/blob/v1.27.0/LICENSE))
|
||||
- [go.opentelemetry.io/otel/trace](https://pkg.go.dev/go.opentelemetry.io/otel/trace) ([BSD-3-Clause](https://github.com/open-telemetry/opentelemetry-go/blob/trace/v1.38.0/trace/LICENSE))
|
||||
- [go.yaml.in/yaml/v3](https://pkg.go.dev/go.yaml.in/yaml/v3) ([MIT](https://github.com/yaml/go-yaml/blob/v3.0.4/LICENSE))
|
||||
- [golang.org/x/crypto](https://pkg.go.dev/golang.org/x/crypto) ([BSD-3-Clause](https://cs.opensource.google/go/x/crypto/+/v0.46.0:LICENSE))
|
||||
- [golang.org/x/exp](https://pkg.go.dev/golang.org/x/exp) ([BSD-3-Clause](https://cs.opensource.google/go/x/exp/+/b7579e27:LICENSE))
|
||||
- [golang.org/x/mod](https://pkg.go.dev/golang.org/x/mod) ([BSD-3-Clause](https://cs.opensource.google/go/x/mod/+/v0.30.0:LICENSE))
|
||||
- [golang.org/x/net](https://pkg.go.dev/golang.org/x/net) ([BSD-3-Clause](https://cs.opensource.google/go/x/net/+/v0.47.0:LICENSE))
|
||||
- [golang.org/x/oauth2](https://pkg.go.dev/golang.org/x/oauth2) ([BSD-3-Clause](https://cs.opensource.google/go/x/oauth2/+/v0.33.0:LICENSE))
|
||||
- [golang.org/x/sync](https://pkg.go.dev/golang.org/x/sync) ([BSD-3-Clause](https://cs.opensource.google/go/x/sync/+/v0.19.0:LICENSE))
|
||||
- [golang.org/x/sync/errgroup](https://pkg.go.dev/golang.org/x/sync/errgroup) ([BSD-3-Clause](https://cs.opensource.google/go/x/sync/+/v0.19.0:LICENSE))
|
||||
- [golang.org/x/sys](https://pkg.go.dev/golang.org/x/sys) ([BSD-3-Clause](https://cs.opensource.google/go/x/sys/+/v0.39.0:LICENSE))
|
||||
- [golang.org/x/term](https://pkg.go.dev/golang.org/x/term) ([BSD-3-Clause](https://cs.opensource.google/go/x/term/+/v0.38.0:LICENSE))
|
||||
- [golang.org/x/text](https://pkg.go.dev/golang.org/x/text) ([BSD-3-Clause](https://cs.opensource.google/go/x/text/+/v0.32.0:LICENSE))
|
||||
- [golang.org/x/time/rate](https://pkg.go.dev/golang.org/x/time/rate) ([BSD-3-Clause](https://cs.opensource.google/go/x/time/+/v0.12.0:LICENSE))
|
||||
- [google.golang.org/api](https://pkg.go.dev/google.golang.org/api) ([BSD-3-Clause](https://github.com/googleapis/google-api-go-client/blob/v0.248.0/LICENSE))
|
||||
- [google.golang.org/api/internal/third_party/uritemplates](https://pkg.go.dev/google.golang.org/api/internal/third_party/uritemplates) ([BSD-3-Clause](https://github.com/googleapis/google-api-go-client/blob/v0.248.0/internal/third_party/uritemplates/LICENSE))
|
||||
- [google.golang.org/genproto/googleapis/api](https://pkg.go.dev/google.golang.org/genproto/googleapis/api) ([Apache-2.0](https://github.com/googleapis/go-genproto/blob/3a174f9686a8/googleapis/api/LICENSE))
|
||||
- [google.golang.org/genproto/googleapis/rpc](https://pkg.go.dev/google.golang.org/genproto/googleapis/rpc) ([Apache-2.0](https://github.com/googleapis/go-genproto/blob/3a174f9686a8/googleapis/rpc/LICENSE))
|
||||
- [google.golang.org/genproto/googleapis/type](https://pkg.go.dev/google.golang.org/genproto/googleapis/type) ([Apache-2.0](https://github.com/googleapis/go-genproto/blob/513f23925822/LICENSE))
|
||||
- [google.golang.org/genproto/googleapis/rpc/status](https://pkg.go.dev/google.golang.org/genproto/googleapis/rpc/status) ([Apache-2.0](https://github.com/googleapis/go-genproto/blob/f26f9409b101/googleapis/rpc/LICENSE))
|
||||
- [google.golang.org/grpc](https://pkg.go.dev/google.golang.org/grpc) ([Apache-2.0](https://github.com/grpc/grpc-go/blob/v1.77.0/LICENSE))
|
||||
- [google.golang.org/protobuf](https://pkg.go.dev/google.golang.org/protobuf) ([BSD-3-Clause](https://github.com/protocolbuffers/protobuf-go/blob/v1.36.10/LICENSE))
|
||||
- [gopkg.in/yaml.v3](https://pkg.go.dev/gopkg.in/yaml.v3) ([MIT](https://github.com/go-yaml/yaml/blob/v3.0.1/LICENSE))
|
||||
- [k8s.io/klog/v2](https://pkg.go.dev/k8s.io/klog/v2) ([Apache-2.0](https://github.com/kubernetes/klog/blob/v2.130.1/LICENSE))
|
||||
|
||||
[cli/cli]: https://github.com/cli/cli
|
||||
|
|
|
|||
202
third-party/cloud.google.com/go/auth/LICENSE
vendored
202
third-party/cloud.google.com/go/auth/LICENSE
vendored
|
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
202
third-party/cloud.google.com/go/iam/LICENSE
vendored
202
third-party/cloud.google.com/go/iam/LICENSE
vendored
|
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
202
third-party/cloud.google.com/go/longrunning/LICENSE
vendored
202
third-party/cloud.google.com/go/longrunning/LICENSE
vendored
|
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
202
third-party/cloud.google.com/go/monitoring/LICENSE
vendored
202
third-party/cloud.google.com/go/monitoring/LICENSE
vendored
|
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
202
third-party/cloud.google.com/go/spanner/LICENSE
vendored
202
third-party/cloud.google.com/go/spanner/LICENSE
vendored
|
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
202
third-party/cloud.google.com/go/storage/LICENSE
vendored
202
third-party/cloud.google.com/go/storage/LICENSE
vendored
|
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
Copyright (c) 2016 Caleb Spare
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2020-2023 Charmbracelet, Inc
|
||||
Copyright (c) 2020-2025 Charmbracelet, Inc
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
Copyright 2018 Anders Rundgren
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -1,201 +0,0 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
Copyright (c) 2016 Felix Geisendörfer (felix@debuggable.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
25
third-party/github.com/fsnotify/fsnotify/LICENSE
vendored
25
third-party/github.com/fsnotify/fsnotify/LICENSE
vendored
|
|
@ -1,25 +0,0 @@
|
|||
Copyright © 2012 The Go Authors. All rights reserved.
|
||||
Copyright © fsnotify Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
* Neither the name of Google Inc. nor the names of its contributors may be used
|
||||
to endorse or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
20
third-party/github.com/go-chi/chi/v5/LICENSE
vendored
20
third-party/github.com/go-chi/chi/v5/LICENSE
vendored
|
|
@ -1,20 +0,0 @@
|
|||
Copyright (c) 2015-present Peter Kieltyka (https://github.com/pkieltyka), Google Inc.
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
202
third-party/github.com/go-jose/go-jose/v4/LICENSE
vendored
202
third-party/github.com/go-jose/go-jose/v4/LICENSE
vendored
|
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
36
third-party/github.com/go-openapi/jsonreference/NOTICE
vendored
Normal file
36
third-party/github.com/go-openapi/jsonreference/NOTICE
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
Copyright 2015-2025 go-swagger maintainers
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
This software library, github.com/go-openapi/jsonpointer, includes software developed
|
||||
by the go-swagger and go-openapi maintainers ("go-swagger maintainers").
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this software except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
This software is copied from, derived from, and inspired by other original software products.
|
||||
It ships with copies of other software which license terms are recalled below.
|
||||
|
||||
The original sofware was authored on 25-02-2013 by sigu-399 (https://github.com/sigu-399, sigu.399@gmail.com).
|
||||
|
||||
github.com/sigh-399/jsonpointer
|
||||
===========================
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2013 sigu-399 ( https://github.com/sigu-399 )
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
Copyright 2013 sigu-399 ( https://github.com/sigu-399 )
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
191
third-party/github.com/golang/groupcache/lru/LICENSE
vendored
191
third-party/github.com/golang/groupcache/lru/LICENSE
vendored
|
|
@ -1,191 +0,0 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and
|
||||
distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright
|
||||
owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities
|
||||
that control, are controlled by, or are under common control with that entity.
|
||||
For the purposes of this definition, "control" means (i) the power, direct or
|
||||
indirect, to cause the direction or management of such entity, whether by
|
||||
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising
|
||||
permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including
|
||||
but not limited to software source code, documentation source, and configuration
|
||||
files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or
|
||||
translation of a Source form, including but not limited to compiled object code,
|
||||
generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made
|
||||
available under the License, as indicated by a copyright notice that is included
|
||||
in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that
|
||||
is based on (or derived from) the Work and for which the editorial revisions,
|
||||
annotations, elaborations, or other modifications represent, as a whole, an
|
||||
original work of authorship. For the purposes of this License, Derivative Works
|
||||
shall not include works that remain separable from, or merely link (or bind by
|
||||
name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version
|
||||
of the Work and any modifications or additions to that Work or Derivative Works
|
||||
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
||||
by the copyright owner or by an individual or Legal Entity authorized to submit
|
||||
on behalf of the copyright owner. For the purposes of this definition,
|
||||
"submitted" means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems, and
|
||||
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
||||
the purpose of discussing and improving the Work, but excluding communication
|
||||
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||
owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
|
||||
of whom a Contribution has been received by Licensor and subsequently
|
||||
incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License.
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the Work and such
|
||||
Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License.
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable (except as stated in this section) patent license to make, have
|
||||
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
|
||||
such license applies only to those patent claims licensable by such Contributor
|
||||
that are necessarily infringed by their Contribution(s) alone or by combination
|
||||
of their Contribution(s) with the Work to which such Contribution(s) was
|
||||
submitted. If You institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
||||
Contribution incorporated within the Work constitutes direct or contributory
|
||||
patent infringement, then any patent licenses granted to You under this License
|
||||
for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution.
|
||||
|
||||
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
||||
in any medium, with or without modifications, and in Source or Object form,
|
||||
provided that You meet the following conditions:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of
|
||||
this License; and
|
||||
You must cause any modified files to carry prominent notices stating that You
|
||||
changed the files; and
|
||||
You must retain, in the Source form of any Derivative Works that You distribute,
|
||||
all copyright, patent, trademark, and attribution notices from the Source form
|
||||
of the Work, excluding those notices that do not pertain to any part of the
|
||||
Derivative Works; and
|
||||
If the Work includes a "NOTICE" text file as part of its distribution, then any
|
||||
Derivative Works that You distribute must include a readable copy of the
|
||||
attribution notices contained within such NOTICE file, excluding those notices
|
||||
that do not pertain to any part of the Derivative Works, in at least one of the
|
||||
following places: within a NOTICE text file distributed as part of the
|
||||
Derivative Works; within the Source form or documentation, if provided along
|
||||
with the Derivative Works; or, within a display generated by the Derivative
|
||||
Works, if and wherever such third-party notices normally appear. The contents of
|
||||
the NOTICE file are for informational purposes only and do not modify the
|
||||
License. You may add Your own attribution notices within Derivative Works that
|
||||
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
||||
provided that such additional attribution notices cannot be construed as
|
||||
modifying the License.
|
||||
You may add Your own copyright statement to Your modifications and may provide
|
||||
additional or different license terms and conditions for use, reproduction, or
|
||||
distribution of Your modifications, or for any such Derivative Works as a whole,
|
||||
provided Your use, reproduction, and distribution of the Work otherwise complies
|
||||
with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions.
|
||||
|
||||
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
||||
for inclusion in the Work by You to the Licensor shall be under the terms and
|
||||
conditions of this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
||||
any separate license agreement you may have executed with Licensor regarding
|
||||
such Contributions.
|
||||
|
||||
6. Trademarks.
|
||||
|
||||
This License does not grant permission to use the trade names, trademarks,
|
||||
service marks, or product names of the Licensor, except as required for
|
||||
reasonable and customary use in describing the origin of the Work and
|
||||
reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, Licensor provides the
|
||||
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
||||
including, without limitation, any warranties or conditions of TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
||||
solely responsible for determining the appropriateness of using or
|
||||
redistributing the Work and assume any risks associated with Your exercise of
|
||||
permissions under this License.
|
||||
|
||||
8. Limitation of Liability.
|
||||
|
||||
In no event and under no legal theory, whether in tort (including negligence),
|
||||
contract, or otherwise, unless required by applicable law (such as deliberate
|
||||
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special, incidental,
|
||||
or consequential damages of any character arising as a result of this License or
|
||||
out of the use or inability to use the Work (including but not limited to
|
||||
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
||||
any and all other commercial damages or losses), even if such Contributor has
|
||||
been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability.
|
||||
|
||||
While redistributing the Work or Derivative Works thereof, You may choose to
|
||||
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
||||
other liability obligations and/or rights consistent with this License. However,
|
||||
in accepting such obligations, You may act only on Your own behalf and on Your
|
||||
sole responsibility, not on behalf of any other Contributor, and only if You
|
||||
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason of your
|
||||
accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work
|
||||
|
||||
To apply the Apache License to your work, attach the following boilerplate
|
||||
notice, with the fields enclosed by brackets "[]" replaced with your own
|
||||
identifying information. (Don't include the brackets!) The text should be
|
||||
enclosed in the appropriate comment syntax for the file format. We also
|
||||
recommend that a file or class name and description of purpose be included on
|
||||
the same "printed page" as the copyright notice for easier identification within
|
||||
third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
27
third-party/github.com/google/go-cmp/cmp/LICENSE
vendored
27
third-party/github.com/google/go-cmp/cmp/LICENSE
vendored
|
|
@ -1,27 +0,0 @@
|
|||
Copyright (c) 2017 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
202
third-party/github.com/google/s2a-go/LICENSE.md
vendored
202
third-party/github.com/google/s2a-go/LICENSE.md
vendored
|
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
Copyright 2016, Google Inc.
|
||||
All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
name: build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
tags:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: set up go 1.19
|
||||
uses: actions/setup-go@6edd4406fa81c3da01a34fa6f6343087c207a568 # v3.5.0
|
||||
with:
|
||||
go-version: 1.19
|
||||
id: go
|
||||
|
||||
- name: checkout
|
||||
uses: actions/checkout@ac593985615ec2ede58e132d2e21d2b1cbd6127c # v3.3.0
|
||||
|
||||
- name: build and test
|
||||
run: |
|
||||
go test -timeout=60s -race ./...
|
||||
go build -race ./...
|
||||
|
||||
- name: build and test ARC
|
||||
working-directory: ./arc
|
||||
run: |
|
||||
go test -timeout=60s -race
|
||||
go build -race
|
||||
|
||||
- name: install golangci-lint
|
||||
run: curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s -- -b $GITHUB_WORKSPACE v1.53.3
|
||||
|
||||
- name: run golangci-lint
|
||||
run: $GITHUB_WORKSPACE/golangci-lint run --out-format=github-actions ./... ./simplelru/... ./expirable/...
|
||||
|
||||
- name: run golangci-lint on ARC
|
||||
working-directory: ./arc
|
||||
run: $GITHUB_WORKSPACE/golangci-lint run --out-format=github-actions ./...
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
# Copyright (c) HashiCorp, Inc.
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
linters:
|
||||
fast: false
|
||||
disable-all: true
|
||||
enable:
|
||||
- revive
|
||||
- megacheck
|
||||
- govet
|
||||
- unconvert
|
||||
- gas
|
||||
- gocyclo
|
||||
- dupl
|
||||
- misspell
|
||||
- unparam
|
||||
- unused
|
||||
- typecheck
|
||||
- ineffassign
|
||||
# - stylecheck
|
||||
- exportloopref
|
||||
- gocritic
|
||||
- nakedret
|
||||
- gosimple
|
||||
- prealloc
|
||||
|
||||
# golangci-lint configuration file
|
||||
linters-settings:
|
||||
revive:
|
||||
ignore-generated-header: true
|
||||
severity: warning
|
||||
rules:
|
||||
- name: package-comments
|
||||
severity: warning
|
||||
disabled: true
|
||||
- name: exported
|
||||
severity: warning
|
||||
disabled: false
|
||||
arguments: ["checkPrivateReceivers", "disableStutteringCheck"]
|
||||
|
||||
issues:
|
||||
exclude-use-default: false
|
||||
exclude-rules:
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- dupl
|
||||
267
third-party/github.com/hashicorp/golang-lru/v2/2q.go
vendored
267
third-party/github.com/hashicorp/golang-lru/v2/2q.go
vendored
|
|
@ -1,267 +0,0 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package lru
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/golang-lru/v2/simplelru"
|
||||
)
|
||||
|
||||
const (
|
||||
// Default2QRecentRatio is the ratio of the 2Q cache dedicated
|
||||
// to recently added entries that have only been accessed once.
|
||||
Default2QRecentRatio = 0.25
|
||||
|
||||
// Default2QGhostEntries is the default ratio of ghost
|
||||
// entries kept to track entries recently evicted
|
||||
Default2QGhostEntries = 0.50
|
||||
)
|
||||
|
||||
// TwoQueueCache is a thread-safe fixed size 2Q cache.
|
||||
// 2Q is an enhancement over the standard LRU cache
|
||||
// in that it tracks both frequently and recently used
|
||||
// entries separately. This avoids a burst in access to new
|
||||
// entries from evicting frequently used entries. It adds some
|
||||
// additional tracking overhead to the standard LRU cache, and is
|
||||
// computationally about 2x the cost, and adds some metadata over
|
||||
// head. The ARCCache is similar, but does not require setting any
|
||||
// parameters.
|
||||
type TwoQueueCache[K comparable, V any] struct {
|
||||
size int
|
||||
recentSize int
|
||||
recentRatio float64
|
||||
ghostRatio float64
|
||||
|
||||
recent simplelru.LRUCache[K, V]
|
||||
frequent simplelru.LRUCache[K, V]
|
||||
recentEvict simplelru.LRUCache[K, struct{}]
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// New2Q creates a new TwoQueueCache using the default
|
||||
// values for the parameters.
|
||||
func New2Q[K comparable, V any](size int) (*TwoQueueCache[K, V], error) {
|
||||
return New2QParams[K, V](size, Default2QRecentRatio, Default2QGhostEntries)
|
||||
}
|
||||
|
||||
// New2QParams creates a new TwoQueueCache using the provided
|
||||
// parameter values.
|
||||
func New2QParams[K comparable, V any](size int, recentRatio, ghostRatio float64) (*TwoQueueCache[K, V], error) {
|
||||
if size <= 0 {
|
||||
return nil, errors.New("invalid size")
|
||||
}
|
||||
if recentRatio < 0.0 || recentRatio > 1.0 {
|
||||
return nil, errors.New("invalid recent ratio")
|
||||
}
|
||||
if ghostRatio < 0.0 || ghostRatio > 1.0 {
|
||||
return nil, errors.New("invalid ghost ratio")
|
||||
}
|
||||
|
||||
// Determine the sub-sizes
|
||||
recentSize := int(float64(size) * recentRatio)
|
||||
evictSize := int(float64(size) * ghostRatio)
|
||||
|
||||
// Allocate the LRUs
|
||||
recent, err := simplelru.NewLRU[K, V](size, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
frequent, err := simplelru.NewLRU[K, V](size, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
recentEvict, err := simplelru.NewLRU[K, struct{}](evictSize, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Initialize the cache
|
||||
c := &TwoQueueCache[K, V]{
|
||||
size: size,
|
||||
recentSize: recentSize,
|
||||
recentRatio: recentRatio,
|
||||
ghostRatio: ghostRatio,
|
||||
recent: recent,
|
||||
frequent: frequent,
|
||||
recentEvict: recentEvict,
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Get looks up a key's value from the cache.
|
||||
func (c *TwoQueueCache[K, V]) Get(key K) (value V, ok bool) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
// Check if this is a frequent value
|
||||
if val, ok := c.frequent.Get(key); ok {
|
||||
return val, ok
|
||||
}
|
||||
|
||||
// If the value is contained in recent, then we
|
||||
// promote it to frequent
|
||||
if val, ok := c.recent.Peek(key); ok {
|
||||
c.recent.Remove(key)
|
||||
c.frequent.Add(key, val)
|
||||
return val, ok
|
||||
}
|
||||
|
||||
// No hit
|
||||
return
|
||||
}
|
||||
|
||||
// Add adds a value to the cache.
|
||||
func (c *TwoQueueCache[K, V]) Add(key K, value V) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
// Check if the value is frequently used already,
|
||||
// and just update the value
|
||||
if c.frequent.Contains(key) {
|
||||
c.frequent.Add(key, value)
|
||||
return
|
||||
}
|
||||
|
||||
// Check if the value is recently used, and promote
|
||||
// the value into the frequent list
|
||||
if c.recent.Contains(key) {
|
||||
c.recent.Remove(key)
|
||||
c.frequent.Add(key, value)
|
||||
return
|
||||
}
|
||||
|
||||
// If the value was recently evicted, add it to the
|
||||
// frequently used list
|
||||
if c.recentEvict.Contains(key) {
|
||||
c.ensureSpace(true)
|
||||
c.recentEvict.Remove(key)
|
||||
c.frequent.Add(key, value)
|
||||
return
|
||||
}
|
||||
|
||||
// Add to the recently seen list
|
||||
c.ensureSpace(false)
|
||||
c.recent.Add(key, value)
|
||||
}
|
||||
|
||||
// ensureSpace is used to ensure we have space in the cache
|
||||
func (c *TwoQueueCache[K, V]) ensureSpace(recentEvict bool) {
|
||||
// If we have space, nothing to do
|
||||
recentLen := c.recent.Len()
|
||||
freqLen := c.frequent.Len()
|
||||
if recentLen+freqLen < c.size {
|
||||
return
|
||||
}
|
||||
|
||||
// If the recent buffer is larger than
|
||||
// the target, evict from there
|
||||
if recentLen > 0 && (recentLen > c.recentSize || (recentLen == c.recentSize && !recentEvict)) {
|
||||
k, _, _ := c.recent.RemoveOldest()
|
||||
c.recentEvict.Add(k, struct{}{})
|
||||
return
|
||||
}
|
||||
|
||||
// Remove from the frequent list otherwise
|
||||
c.frequent.RemoveOldest()
|
||||
}
|
||||
|
||||
// Len returns the number of items in the cache.
|
||||
func (c *TwoQueueCache[K, V]) Len() int {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
return c.recent.Len() + c.frequent.Len()
|
||||
}
|
||||
|
||||
// Resize changes the cache size.
|
||||
func (c *TwoQueueCache[K, V]) Resize(size int) (evicted int) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
// Recalculate the sub-sizes
|
||||
recentSize := int(float64(size) * c.recentRatio)
|
||||
evictSize := int(float64(size) * c.ghostRatio)
|
||||
c.size = size
|
||||
c.recentSize = recentSize
|
||||
|
||||
// ensureSpace
|
||||
diff := c.recent.Len() + c.frequent.Len() - size
|
||||
if diff < 0 {
|
||||
diff = 0
|
||||
}
|
||||
for i := 0; i < diff; i++ {
|
||||
c.ensureSpace(true)
|
||||
}
|
||||
|
||||
// Reallocate the LRUs
|
||||
c.recent.Resize(size)
|
||||
c.frequent.Resize(size)
|
||||
c.recentEvict.Resize(evictSize)
|
||||
|
||||
return diff
|
||||
}
|
||||
|
||||
// Keys returns a slice of the keys in the cache.
|
||||
// The frequently used keys are first in the returned slice.
|
||||
func (c *TwoQueueCache[K, V]) Keys() []K {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
k1 := c.frequent.Keys()
|
||||
k2 := c.recent.Keys()
|
||||
return append(k1, k2...)
|
||||
}
|
||||
|
||||
// Values returns a slice of the values in the cache.
|
||||
// The frequently used values are first in the returned slice.
|
||||
func (c *TwoQueueCache[K, V]) Values() []V {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
v1 := c.frequent.Values()
|
||||
v2 := c.recent.Values()
|
||||
return append(v1, v2...)
|
||||
}
|
||||
|
||||
// Remove removes the provided key from the cache.
|
||||
func (c *TwoQueueCache[K, V]) Remove(key K) {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
if c.frequent.Remove(key) {
|
||||
return
|
||||
}
|
||||
if c.recent.Remove(key) {
|
||||
return
|
||||
}
|
||||
if c.recentEvict.Remove(key) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Purge is used to completely clear the cache.
|
||||
func (c *TwoQueueCache[K, V]) Purge() {
|
||||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
c.recent.Purge()
|
||||
c.frequent.Purge()
|
||||
c.recentEvict.Purge()
|
||||
}
|
||||
|
||||
// Contains is used to check if the cache contains a key
|
||||
// without updating recency or frequency.
|
||||
func (c *TwoQueueCache[K, V]) Contains(key K) bool {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
return c.frequent.Contains(key) || c.recent.Contains(key)
|
||||
}
|
||||
|
||||
// Peek is used to inspect the cache value of a key
|
||||
// without updating recency or frequency.
|
||||
func (c *TwoQueueCache[K, V]) Peek(key K) (value V, ok bool) {
|
||||
c.lock.RLock()
|
||||
defer c.lock.RUnlock()
|
||||
if val, ok := c.frequent.Peek(key); ok {
|
||||
return val, ok
|
||||
}
|
||||
return c.recent.Peek(key)
|
||||
}
|
||||
|
|
@ -1,375 +0,0 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package lru
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Benchmark2Q_Rand(b *testing.B) {
|
||||
l, err := New2Q[int64, int64](8192)
|
||||
if err != nil {
|
||||
b.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
trace := make([]int64, b.N*2)
|
||||
for i := 0; i < b.N*2; i++ {
|
||||
trace[i] = getRand(b) % 32768
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
var hit, miss int
|
||||
for i := 0; i < 2*b.N; i++ {
|
||||
if i%2 == 0 {
|
||||
l.Add(trace[i], trace[i])
|
||||
} else {
|
||||
if _, ok := l.Get(trace[i]); ok {
|
||||
hit++
|
||||
} else {
|
||||
miss++
|
||||
}
|
||||
}
|
||||
}
|
||||
b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(hit+miss))
|
||||
}
|
||||
|
||||
func Benchmark2Q_Freq(b *testing.B) {
|
||||
l, err := New2Q[int64, int64](8192)
|
||||
if err != nil {
|
||||
b.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
trace := make([]int64, b.N*2)
|
||||
for i := 0; i < b.N*2; i++ {
|
||||
if i%2 == 0 {
|
||||
trace[i] = getRand(b) % 16384
|
||||
} else {
|
||||
trace[i] = getRand(b) % 32768
|
||||
}
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
l.Add(trace[i], trace[i])
|
||||
}
|
||||
var hit, miss int
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, ok := l.Get(trace[i]); ok {
|
||||
hit++
|
||||
} else {
|
||||
miss++
|
||||
}
|
||||
}
|
||||
b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(hit+miss))
|
||||
}
|
||||
|
||||
func Test2Q_RandomOps(t *testing.T) {
|
||||
size := 128
|
||||
l, err := New2Q[int64, int64](128)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
n := 200000
|
||||
for i := 0; i < n; i++ {
|
||||
key := getRand(t) % 512
|
||||
r := getRand(t)
|
||||
switch r % 3 {
|
||||
case 0:
|
||||
l.Add(key, key)
|
||||
case 1:
|
||||
l.Get(key)
|
||||
case 2:
|
||||
l.Remove(key)
|
||||
}
|
||||
|
||||
if l.recent.Len()+l.frequent.Len() > size {
|
||||
t.Fatalf("bad: recent: %d freq: %d",
|
||||
l.recent.Len(), l.frequent.Len())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test2Q_Get_RecentToFrequent(t *testing.T) {
|
||||
l, err := New2Q[int, int](128)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Touch all the entries, should be in t1
|
||||
for i := 0; i < 128; i++ {
|
||||
l.Add(i, i)
|
||||
}
|
||||
if n := l.recent.Len(); n != 128 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
if n := l.frequent.Len(); n != 0 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
|
||||
// Get should upgrade to t2
|
||||
for i := 0; i < 128; i++ {
|
||||
if _, ok := l.Get(i); !ok {
|
||||
t.Fatalf("missing: %d", i)
|
||||
}
|
||||
}
|
||||
if n := l.recent.Len(); n != 0 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
if n := l.frequent.Len(); n != 128 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
|
||||
// Get be from t2
|
||||
for i := 0; i < 128; i++ {
|
||||
if _, ok := l.Get(i); !ok {
|
||||
t.Fatalf("missing: %d", i)
|
||||
}
|
||||
}
|
||||
if n := l.recent.Len(); n != 0 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
if n := l.frequent.Len(); n != 128 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
}
|
||||
|
||||
func Test2Q_Add_RecentToFrequent(t *testing.T) {
|
||||
l, err := New2Q[int, int](128)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Add initially to recent
|
||||
l.Add(1, 1)
|
||||
if n := l.recent.Len(); n != 1 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
if n := l.frequent.Len(); n != 0 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
|
||||
// Add should upgrade to frequent
|
||||
l.Add(1, 1)
|
||||
if n := l.recent.Len(); n != 0 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
if n := l.frequent.Len(); n != 1 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
|
||||
// Add should remain in frequent
|
||||
l.Add(1, 1)
|
||||
if n := l.recent.Len(); n != 0 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
if n := l.frequent.Len(); n != 1 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
}
|
||||
|
||||
func Test2Q_Add_RecentEvict(t *testing.T) {
|
||||
l, err := New2Q[int, int](4)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Add 1,2,3,4,5 -> Evict 1
|
||||
l.Add(1, 1)
|
||||
l.Add(2, 2)
|
||||
l.Add(3, 3)
|
||||
l.Add(4, 4)
|
||||
l.Add(5, 5)
|
||||
if n := l.recent.Len(); n != 4 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
if n := l.recentEvict.Len(); n != 1 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
if n := l.frequent.Len(); n != 0 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
|
||||
// Pull in the recently evicted
|
||||
l.Add(1, 1)
|
||||
if n := l.recent.Len(); n != 3 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
if n := l.recentEvict.Len(); n != 1 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
if n := l.frequent.Len(); n != 1 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
|
||||
// Add 6, should cause another recent evict
|
||||
l.Add(6, 6)
|
||||
if n := l.recent.Len(); n != 3 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
if n := l.recentEvict.Len(); n != 2 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
if n := l.frequent.Len(); n != 1 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
}
|
||||
|
||||
func Test2Q_Resize(t *testing.T) {
|
||||
l, err := New2Q[int, int](100)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Touch all the entries, should be in t1
|
||||
for i := 0; i < 100; i++ {
|
||||
l.Add(i, i)
|
||||
}
|
||||
|
||||
evicted := l.Resize(50)
|
||||
if evicted != 50 {
|
||||
t.Fatalf("bad: %d", evicted)
|
||||
}
|
||||
|
||||
if n := l.recent.Len(); n != 50 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
if n := l.frequent.Len(); n != 0 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
|
||||
l, err = New2Q[int, int](100)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
for i := 0; i < 100; i++ {
|
||||
l.Add(i, i)
|
||||
}
|
||||
|
||||
for i := 0; i < 50; i++ {
|
||||
l.Add(i, i)
|
||||
}
|
||||
|
||||
evicted = l.Resize(50)
|
||||
if evicted != 50 {
|
||||
t.Fatalf("bad: %d", evicted)
|
||||
}
|
||||
|
||||
if n := l.recent.Len(); n != 12 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
if n := l.frequent.Len(); n != 38 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
|
||||
l, err = New2Q[int, int](100)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
for i := 0; i < 100; i++ {
|
||||
l.Add(i, i)
|
||||
l.Add(i, i)
|
||||
}
|
||||
|
||||
evicted = l.Resize(50)
|
||||
if evicted != 50 {
|
||||
t.Fatalf("bad: %d", evicted)
|
||||
}
|
||||
|
||||
if n := l.recent.Len(); n != 0 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
if n := l.frequent.Len(); n != 50 {
|
||||
t.Fatalf("bad: %d", n)
|
||||
}
|
||||
}
|
||||
|
||||
func Test2Q(t *testing.T) {
|
||||
l, err := New2Q[int, int](128)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
for i := 0; i < 256; i++ {
|
||||
l.Add(i, i)
|
||||
}
|
||||
if l.Len() != 128 {
|
||||
t.Fatalf("bad len: %v", l.Len())
|
||||
}
|
||||
|
||||
for i, k := range l.Keys() {
|
||||
if v, ok := l.Get(k); !ok || v != k || v != i+128 {
|
||||
t.Fatalf("bad key: %v", k)
|
||||
}
|
||||
}
|
||||
for i, v := range l.Values() {
|
||||
if v != i+128 {
|
||||
t.Fatalf("bad key: %v", v)
|
||||
}
|
||||
}
|
||||
for i := 0; i < 128; i++ {
|
||||
if _, ok := l.Get(i); ok {
|
||||
t.Fatalf("should be evicted")
|
||||
}
|
||||
}
|
||||
for i := 128; i < 256; i++ {
|
||||
if _, ok := l.Get(i); !ok {
|
||||
t.Fatalf("should not be evicted")
|
||||
}
|
||||
}
|
||||
for i := 128; i < 192; i++ {
|
||||
l.Remove(i)
|
||||
if _, ok := l.Get(i); ok {
|
||||
t.Fatalf("should be deleted")
|
||||
}
|
||||
}
|
||||
|
||||
l.Purge()
|
||||
if l.Len() != 0 {
|
||||
t.Fatalf("bad len: %v", l.Len())
|
||||
}
|
||||
if _, ok := l.Get(200); ok {
|
||||
t.Fatalf("should contain nothing")
|
||||
}
|
||||
}
|
||||
|
||||
// Test that Contains doesn't update recent-ness
|
||||
func Test2Q_Contains(t *testing.T) {
|
||||
l, err := New2Q[int, int](2)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
l.Add(1, 1)
|
||||
l.Add(2, 2)
|
||||
if !l.Contains(1) {
|
||||
t.Errorf("1 should be contained")
|
||||
}
|
||||
|
||||
l.Add(3, 3)
|
||||
if l.Contains(1) {
|
||||
t.Errorf("Contains should not have updated recent-ness of 1")
|
||||
}
|
||||
}
|
||||
|
||||
// Test that Peek doesn't update recent-ness
|
||||
func Test2Q_Peek(t *testing.T) {
|
||||
l, err := New2Q[int, int](2)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
l.Add(1, 1)
|
||||
l.Add(2, 2)
|
||||
if v, ok := l.Peek(1); !ok || v != 1 {
|
||||
t.Errorf("1 should be set to 1: %v, %v", v, ok)
|
||||
}
|
||||
|
||||
l.Add(3, 3)
|
||||
if l.Contains(1) {
|
||||
t.Errorf("should not have updated recent-ness of 1")
|
||||
}
|
||||
}
|
||||
|
|
@ -1,364 +0,0 @@
|
|||
Copyright (c) 2014 HashiCorp, Inc.
|
||||
|
||||
Mozilla Public License, version 2.0
|
||||
|
||||
1. Definitions
|
||||
|
||||
1.1. "Contributor"
|
||||
|
||||
means each individual or legal entity that creates, contributes to the
|
||||
creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
|
||||
means the combination of the Contributions of others (if any) used by a
|
||||
Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
|
||||
means Source Code Form to which the initial Contributor has attached the
|
||||
notice in Exhibit A, the Executable Form of such Source Code Form, and
|
||||
Modifications of such Source Code Form, in each case including portions
|
||||
thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
a. that the initial Contributor has attached the notice described in
|
||||
Exhibit B to the Covered Software; or
|
||||
|
||||
b. that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the terms of
|
||||
a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
|
||||
means a work that combines Covered Software with other material, in a
|
||||
separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
|
||||
means having the right to grant, to the maximum extent possible, whether
|
||||
at the time of the initial grant or subsequently, any and all of the
|
||||
rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
|
||||
means any of the following:
|
||||
|
||||
a. any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered Software; or
|
||||
|
||||
b. any new file in Source Code Form that contains any Covered Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the License,
|
||||
by the making, using, selling, offering for sale, having made, import,
|
||||
or transfer of either its Contributions or its Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
|
||||
means either the GNU General Public License, Version 2.0, the GNU Lesser
|
||||
General Public License, Version 2.1, the GNU Affero General Public
|
||||
License, Version 3.0, or any later versions of those licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that controls, is
|
||||
controlled by, or is under common control with You. For purposes of this
|
||||
definition, "control" means (a) the power, direct or indirect, to cause
|
||||
the direction or management of such entity, whether by contract or
|
||||
otherwise, or (b) ownership of more than fifty percent (50%) of the
|
||||
outstanding shares or beneficial ownership of such entity.
|
||||
|
||||
|
||||
2. License Grants and Conditions
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
a. under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
b. under Patent Claims of such Contributor to make, use, sell, offer for
|
||||
sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
a. for any code that a Contributor has removed from Covered Software; or
|
||||
|
||||
b. for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
c. under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights to
|
||||
grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in
|
||||
Section 2.1.
|
||||
|
||||
|
||||
3. Responsibilities
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
a. such Covered Software must also be made available in Source Code Form,
|
||||
as described in Section 3.1, and You must inform recipients of the
|
||||
Executable Form how they can obtain a copy of such Source Code Form by
|
||||
reasonable means in a timely manner, at a charge no more than the cost
|
||||
of distribution to the recipient; and
|
||||
|
||||
b. You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter the
|
||||
recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty, or
|
||||
limitations of liability) contained within the Source Code Form of the
|
||||
Covered Software, except that You may alter any license notices to the
|
||||
extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this License
|
||||
with respect to some or all of the Covered Software due to statute,
|
||||
judicial order, or regulation then You must: (a) comply with the terms of
|
||||
this License to the maximum extent possible; and (b) describe the
|
||||
limitations and the code they affect. Such description must be placed in a
|
||||
text file included with all distributions of the Covered Software under
|
||||
this License. Except to the extent prohibited by statute or regulation,
|
||||
such description must be sufficiently detailed for a recipient of ordinary
|
||||
skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically if You
|
||||
fail to comply with any of its terms. However, if You become compliant,
|
||||
then the rights granted under this License from a particular Contributor
|
||||
are reinstated (a) provisionally, unless and until such Contributor
|
||||
explicitly and finally terminates Your grants, and (b) on an ongoing
|
||||
basis, if such Contributor fails to notify You of the non-compliance by
|
||||
some reasonable means prior to 60 days after You have come back into
|
||||
compliance. Moreover, Your grants from a particular Contributor are
|
||||
reinstated on an ongoing basis if such Contributor notifies You of the
|
||||
non-compliance by some reasonable means, this is the first time You have
|
||||
received notice of non-compliance with this License from such
|
||||
Contributor, and You become compliant prior to 30 days after Your receipt
|
||||
of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user
|
||||
license agreements (excluding distributors and resellers) which have been
|
||||
validly granted by You or Your distributors under this License prior to
|
||||
termination shall survive termination.
|
||||
|
||||
6. Disclaimer of Warranty
|
||||
|
||||
Covered Software is provided under this License on an "as is" basis,
|
||||
without warranty of any kind, either expressed, implied, or statutory,
|
||||
including, without limitation, warranties that the Covered Software is free
|
||||
of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||
The entire risk as to the quality and performance of the Covered Software
|
||||
is with You. Should any Covered Software prove defective in any respect,
|
||||
You (not any Contributor) assume the cost of any necessary servicing,
|
||||
repair, or correction. This disclaimer of warranty constitutes an essential
|
||||
part of this License. No use of any Covered Software is authorized under
|
||||
this License except under this disclaimer.
|
||||
|
||||
7. Limitation of Liability
|
||||
|
||||
Under no circumstances and under no legal theory, whether tort (including
|
||||
negligence), contract, or otherwise, shall any Contributor, or anyone who
|
||||
distributes Covered Software as permitted above, be liable to You for any
|
||||
direct, indirect, special, incidental, or consequential damages of any
|
||||
character including, without limitation, damages for lost profits, loss of
|
||||
goodwill, work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses, even if such party shall have been
|
||||
informed of the possibility of such damages. This limitation of liability
|
||||
shall not apply to liability for death or personal injury resulting from
|
||||
such party's negligence to the extent applicable law prohibits such
|
||||
limitation. Some jurisdictions do not allow the exclusion or limitation of
|
||||
incidental or consequential damages, so this exclusion and limitation may
|
||||
not apply to You.
|
||||
|
||||
8. Litigation
|
||||
|
||||
Any litigation relating to this License may be brought only in the courts
|
||||
of a jurisdiction where the defendant maintains its principal place of
|
||||
business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions. Nothing
|
||||
in this Section shall prevent a party's ability to bring cross-claims or
|
||||
counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides that
|
||||
the language of a contract shall be construed against the drafter shall not
|
||||
be used to construe this License against a Contributor.
|
||||
|
||||
|
||||
10. Versions of the License
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses If You choose to distribute Source Code Form that is
|
||||
Incompatible With Secondary Licenses under the terms of this version of
|
||||
the License, the notice described in Exhibit B of this License must be
|
||||
attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
|
||||
This Source Code Form is subject to the
|
||||
terms of the Mozilla Public License, v.
|
||||
2.0. If a copy of the MPL was not
|
||||
distributed with this file, You can
|
||||
obtain one at
|
||||
http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular file,
|
||||
then You may include the notice in a location (such as a LICENSE file in a
|
||||
relevant directory) where a recipient would be likely to look for such a
|
||||
notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
|
||||
This Source Code Form is "Incompatible
|
||||
With Secondary Licenses", as defined by
|
||||
the Mozilla Public License, v. 2.0.
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
golang-lru
|
||||
==========
|
||||
|
||||
This provides the `lru` package which implements a fixed-size
|
||||
thread safe LRU cache. It is based on the cache in Groupcache.
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
||||
Full docs are available on [Go Packages](https://pkg.go.dev/github.com/hashicorp/golang-lru/v2)
|
||||
|
||||
LRU cache example
|
||||
=================
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/hashicorp/golang-lru/v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l, _ := lru.New[int, any](128)
|
||||
for i := 0; i < 256; i++ {
|
||||
l.Add(i, nil)
|
||||
}
|
||||
if l.Len() != 128 {
|
||||
panic(fmt.Sprintf("bad len: %v", l.Len()))
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Expirable LRU cache example
|
||||
===========================
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/golang-lru/v2/expirable"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// make cache with 10ms TTL and 5 max keys
|
||||
cache := expirable.NewLRU[string, string](5, nil, time.Millisecond*10)
|
||||
|
||||
|
||||
// set value under key1.
|
||||
cache.Add("key1", "val1")
|
||||
|
||||
// get value under key1
|
||||
r, ok := cache.Get("key1")
|
||||
|
||||
// check for OK value
|
||||
if ok {
|
||||
fmt.Printf("value before expiration is found: %v, value: %q\n", ok, r)
|
||||
}
|
||||
|
||||
// wait for cache to expire
|
||||
time.Sleep(time.Millisecond * 12)
|
||||
|
||||
// get value under key1 after key expiration
|
||||
r, ok = cache.Get("key1")
|
||||
fmt.Printf("value after expiration is found: %v, value: %q\n", ok, r)
|
||||
|
||||
// set value under key2, would evict old entry because it is already expired.
|
||||
cache.Add("key2", "val2")
|
||||
|
||||
fmt.Printf("Cache len: %d\n", cache.Len())
|
||||
// Output:
|
||||
// value before expiration is found: true, value: "val1"
|
||||
// value after expiration is found: false, value: ""
|
||||
// Cache len: 1
|
||||
}
|
||||
```
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
// Package lru provides three different LRU caches of varying sophistication.
|
||||
//
|
||||
// Cache is a simple LRU cache. It is based on the LRU implementation in
|
||||
// groupcache: https://github.com/golang/groupcache/tree/master/lru
|
||||
//
|
||||
// TwoQueueCache tracks frequently used and recently used entries separately.
|
||||
// This avoids a burst of accesses from taking out frequently used entries, at
|
||||
// the cost of about 2x computational overhead and some extra bookkeeping.
|
||||
//
|
||||
// ARCCache is an adaptive replacement cache. It tracks recent evictions as well
|
||||
// as recent usage in both the frequent and recent caches. Its computational
|
||||
// overhead is comparable to TwoQueueCache, but the memory overhead is linear
|
||||
// with the size of the cache.
|
||||
//
|
||||
// ARC has been patented by IBM, so do not use it if that is problematic for
|
||||
// your program. For this reason, it is in a separate go module contained within
|
||||
// this repository.
|
||||
//
|
||||
// All caches in this package take locks while operating, and are therefore
|
||||
// thread-safe for consumers.
|
||||
package lru
|
||||
|
|
@ -1,338 +0,0 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package expirable
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/golang-lru/v2/internal"
|
||||
)
|
||||
|
||||
// EvictCallback is used to get a callback when a cache entry is evicted
|
||||
type EvictCallback[K comparable, V any] func(key K, value V)
|
||||
|
||||
// LRU implements a thread-safe LRU with expirable entries.
|
||||
type LRU[K comparable, V any] struct {
|
||||
size int
|
||||
evictList *internal.LruList[K, V]
|
||||
items map[K]*internal.Entry[K, V]
|
||||
onEvict EvictCallback[K, V]
|
||||
|
||||
// expirable options
|
||||
mu sync.Mutex
|
||||
ttl time.Duration
|
||||
done chan struct{}
|
||||
|
||||
// buckets for expiration
|
||||
buckets []bucket[K, V]
|
||||
// uint8 because it's number between 0 and numBuckets
|
||||
nextCleanupBucket uint8
|
||||
}
|
||||
|
||||
// bucket is a container for holding entries to be expired
|
||||
type bucket[K comparable, V any] struct {
|
||||
entries map[K]*internal.Entry[K, V]
|
||||
newestEntry time.Time
|
||||
}
|
||||
|
||||
// noEvictionTTL - very long ttl to prevent eviction
|
||||
const noEvictionTTL = time.Hour * 24 * 365 * 10
|
||||
|
||||
// because of uint8 usage for nextCleanupBucket, should not exceed 256.
|
||||
// casting it as uint8 explicitly requires type conversions in multiple places
|
||||
const numBuckets = 100
|
||||
|
||||
// NewLRU returns a new thread-safe cache with expirable entries.
|
||||
//
|
||||
// Size parameter set to 0 makes cache of unlimited size, e.g. turns LRU mechanism off.
|
||||
//
|
||||
// Providing 0 TTL turns expiring off.
|
||||
//
|
||||
// Delete expired entries every 1/100th of ttl value. Goroutine which deletes expired entries runs indefinitely.
|
||||
func NewLRU[K comparable, V any](size int, onEvict EvictCallback[K, V], ttl time.Duration) *LRU[K, V] {
|
||||
if size < 0 {
|
||||
size = 0
|
||||
}
|
||||
if ttl <= 0 {
|
||||
ttl = noEvictionTTL
|
||||
}
|
||||
|
||||
res := LRU[K, V]{
|
||||
ttl: ttl,
|
||||
size: size,
|
||||
evictList: internal.NewList[K, V](),
|
||||
items: make(map[K]*internal.Entry[K, V]),
|
||||
onEvict: onEvict,
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
|
||||
// initialize the buckets
|
||||
res.buckets = make([]bucket[K, V], numBuckets)
|
||||
for i := 0; i < numBuckets; i++ {
|
||||
res.buckets[i] = bucket[K, V]{entries: make(map[K]*internal.Entry[K, V])}
|
||||
}
|
||||
|
||||
// enable deleteExpired() running in separate goroutine for cache with non-zero TTL
|
||||
//
|
||||
// Important: done channel is never closed, so deleteExpired() goroutine will never exit,
|
||||
// it's decided to add functionality to close it in the version later than v2.
|
||||
if res.ttl != noEvictionTTL {
|
||||
go func(done <-chan struct{}) {
|
||||
ticker := time.NewTicker(res.ttl / numBuckets)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-done:
|
||||
return
|
||||
case <-ticker.C:
|
||||
res.deleteExpired()
|
||||
}
|
||||
}
|
||||
}(res.done)
|
||||
}
|
||||
return &res
|
||||
}
|
||||
|
||||
// Purge clears the cache completely.
|
||||
// onEvict is called for each evicted key.
|
||||
func (c *LRU[K, V]) Purge() {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
for k, v := range c.items {
|
||||
if c.onEvict != nil {
|
||||
c.onEvict(k, v.Value)
|
||||
}
|
||||
delete(c.items, k)
|
||||
}
|
||||
for _, b := range c.buckets {
|
||||
for _, ent := range b.entries {
|
||||
delete(b.entries, ent.Key)
|
||||
}
|
||||
}
|
||||
c.evictList.Init()
|
||||
}
|
||||
|
||||
// Add adds a value to the cache. Returns true if an eviction occurred.
|
||||
// Returns false if there was no eviction: the item was already in the cache,
|
||||
// or the size was not exceeded.
|
||||
func (c *LRU[K, V]) Add(key K, value V) (evicted bool) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
now := time.Now()
|
||||
|
||||
// Check for existing item
|
||||
if ent, ok := c.items[key]; ok {
|
||||
c.evictList.MoveToFront(ent)
|
||||
c.removeFromBucket(ent) // remove the entry from its current bucket as expiresAt is renewed
|
||||
ent.Value = value
|
||||
ent.ExpiresAt = now.Add(c.ttl)
|
||||
c.addToBucket(ent)
|
||||
return false
|
||||
}
|
||||
|
||||
// Add new item
|
||||
ent := c.evictList.PushFrontExpirable(key, value, now.Add(c.ttl))
|
||||
c.items[key] = ent
|
||||
c.addToBucket(ent) // adds the entry to the appropriate bucket and sets entry.expireBucket
|
||||
|
||||
evict := c.size > 0 && c.evictList.Length() > c.size
|
||||
// Verify size not exceeded
|
||||
if evict {
|
||||
c.removeOldest()
|
||||
}
|
||||
return evict
|
||||
}
|
||||
|
||||
// Get looks up a key's value from the cache.
|
||||
func (c *LRU[K, V]) Get(key K) (value V, ok bool) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
var ent *internal.Entry[K, V]
|
||||
if ent, ok = c.items[key]; ok {
|
||||
// Expired item check
|
||||
if time.Now().After(ent.ExpiresAt) {
|
||||
return value, false
|
||||
}
|
||||
c.evictList.MoveToFront(ent)
|
||||
return ent.Value, true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Contains checks if a key is in the cache, without updating the recent-ness
|
||||
// or deleting it for being stale.
|
||||
func (c *LRU[K, V]) Contains(key K) (ok bool) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
_, ok = c.items[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Peek returns the key value (or undefined if not found) without updating
|
||||
// the "recently used"-ness of the key.
|
||||
func (c *LRU[K, V]) Peek(key K) (value V, ok bool) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
var ent *internal.Entry[K, V]
|
||||
if ent, ok = c.items[key]; ok {
|
||||
// Expired item check
|
||||
if time.Now().After(ent.ExpiresAt) {
|
||||
return value, false
|
||||
}
|
||||
return ent.Value, true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Remove removes the provided key from the cache, returning if the
|
||||
// key was contained.
|
||||
func (c *LRU[K, V]) Remove(key K) bool {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if ent, ok := c.items[key]; ok {
|
||||
c.removeElement(ent)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RemoveOldest removes the oldest item from the cache.
|
||||
func (c *LRU[K, V]) RemoveOldest() (key K, value V, ok bool) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if ent := c.evictList.Back(); ent != nil {
|
||||
c.removeElement(ent)
|
||||
return ent.Key, ent.Value, true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetOldest returns the oldest entry
|
||||
func (c *LRU[K, V]) GetOldest() (key K, value V, ok bool) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if ent := c.evictList.Back(); ent != nil {
|
||||
return ent.Key, ent.Value, true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Keys returns a slice of the keys in the cache, from oldest to newest.
|
||||
func (c *LRU[K, V]) Keys() []K {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
keys := make([]K, 0, len(c.items))
|
||||
for ent := c.evictList.Back(); ent != nil; ent = ent.PrevEntry() {
|
||||
keys = append(keys, ent.Key)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
// Values returns a slice of the values in the cache, from oldest to newest.
|
||||
// Expired entries are filtered out.
|
||||
func (c *LRU[K, V]) Values() []V {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
values := make([]V, len(c.items))
|
||||
i := 0
|
||||
now := time.Now()
|
||||
for ent := c.evictList.Back(); ent != nil; ent = ent.PrevEntry() {
|
||||
if now.After(ent.ExpiresAt) {
|
||||
continue
|
||||
}
|
||||
values[i] = ent.Value
|
||||
i++
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
// Len returns the number of items in the cache.
|
||||
func (c *LRU[K, V]) Len() int {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
return c.evictList.Length()
|
||||
}
|
||||
|
||||
// Resize changes the cache size. Size of 0 means unlimited.
|
||||
func (c *LRU[K, V]) Resize(size int) (evicted int) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if size <= 0 {
|
||||
c.size = 0
|
||||
return 0
|
||||
}
|
||||
diff := c.evictList.Length() - size
|
||||
if diff < 0 {
|
||||
diff = 0
|
||||
}
|
||||
for i := 0; i < diff; i++ {
|
||||
c.removeOldest()
|
||||
}
|
||||
c.size = size
|
||||
return diff
|
||||
}
|
||||
|
||||
// Close destroys cleanup goroutine. To clean up the cache, run Purge() before Close().
|
||||
// func (c *LRU[K, V]) Close() {
|
||||
// c.mu.Lock()
|
||||
// defer c.mu.Unlock()
|
||||
// select {
|
||||
// case <-c.done:
|
||||
// return
|
||||
// default:
|
||||
// }
|
||||
// close(c.done)
|
||||
// }
|
||||
|
||||
// removeOldest removes the oldest item from the cache. Has to be called with lock!
|
||||
func (c *LRU[K, V]) removeOldest() {
|
||||
if ent := c.evictList.Back(); ent != nil {
|
||||
c.removeElement(ent)
|
||||
}
|
||||
}
|
||||
|
||||
// removeElement is used to remove a given list element from the cache. Has to be called with lock!
|
||||
func (c *LRU[K, V]) removeElement(e *internal.Entry[K, V]) {
|
||||
c.evictList.Remove(e)
|
||||
delete(c.items, e.Key)
|
||||
c.removeFromBucket(e)
|
||||
if c.onEvict != nil {
|
||||
c.onEvict(e.Key, e.Value)
|
||||
}
|
||||
}
|
||||
|
||||
// deleteExpired deletes expired records from the oldest bucket, waiting for the newest entry
|
||||
// in it to expire first.
|
||||
func (c *LRU[K, V]) deleteExpired() {
|
||||
c.mu.Lock()
|
||||
bucketIdx := c.nextCleanupBucket
|
||||
timeToExpire := time.Until(c.buckets[bucketIdx].newestEntry)
|
||||
// wait for newest entry to expire before cleanup without holding lock
|
||||
if timeToExpire > 0 {
|
||||
c.mu.Unlock()
|
||||
time.Sleep(timeToExpire)
|
||||
c.mu.Lock()
|
||||
}
|
||||
for _, ent := range c.buckets[bucketIdx].entries {
|
||||
c.removeElement(ent)
|
||||
}
|
||||
c.nextCleanupBucket = (c.nextCleanupBucket + 1) % numBuckets
|
||||
c.mu.Unlock()
|
||||
}
|
||||
|
||||
// addToBucket adds entry to expire bucket so that it will be cleaned up when the time comes. Has to be called with lock!
|
||||
func (c *LRU[K, V]) addToBucket(e *internal.Entry[K, V]) {
|
||||
bucketID := (numBuckets + c.nextCleanupBucket - 1) % numBuckets
|
||||
e.ExpireBucket = bucketID
|
||||
c.buckets[bucketID].entries[e.Key] = e
|
||||
if c.buckets[bucketID].newestEntry.Before(e.ExpiresAt) {
|
||||
c.buckets[bucketID].newestEntry = e.ExpiresAt
|
||||
}
|
||||
}
|
||||
|
||||
// removeFromBucket removes the entry from its corresponding bucket. Has to be called with lock!
|
||||
func (c *LRU[K, V]) removeFromBucket(e *internal.Entry[K, V]) {
|
||||
delete(c.buckets[e.ExpireBucket].entries, e.Key)
|
||||
}
|
||||
|
|
@ -1,573 +0,0 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package expirable
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/golang-lru/v2/simplelru"
|
||||
)
|
||||
|
||||
func BenchmarkLRU_Rand_NoExpire(b *testing.B) {
|
||||
l := NewLRU[int64, int64](8192, nil, 0)
|
||||
|
||||
trace := make([]int64, b.N*2)
|
||||
for i := 0; i < b.N*2; i++ {
|
||||
trace[i] = getRand(b) % 32768
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
var hit, miss int
|
||||
for i := 0; i < 2*b.N; i++ {
|
||||
if i%2 == 0 {
|
||||
l.Add(trace[i], trace[i])
|
||||
} else {
|
||||
if _, ok := l.Get(trace[i]); ok {
|
||||
hit++
|
||||
} else {
|
||||
miss++
|
||||
}
|
||||
}
|
||||
}
|
||||
b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(hit+miss))
|
||||
}
|
||||
|
||||
func BenchmarkLRU_Freq_NoExpire(b *testing.B) {
|
||||
l := NewLRU[int64, int64](8192, nil, 0)
|
||||
|
||||
trace := make([]int64, b.N*2)
|
||||
for i := 0; i < b.N*2; i++ {
|
||||
if i%2 == 0 {
|
||||
trace[i] = getRand(b) % 16384
|
||||
} else {
|
||||
trace[i] = getRand(b) % 32768
|
||||
}
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
l.Add(trace[i], trace[i])
|
||||
}
|
||||
var hit, miss int
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, ok := l.Get(trace[i]); ok {
|
||||
hit++
|
||||
} else {
|
||||
miss++
|
||||
}
|
||||
}
|
||||
b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(hit+miss))
|
||||
}
|
||||
|
||||
func BenchmarkLRU_Rand_WithExpire(b *testing.B) {
|
||||
l := NewLRU[int64, int64](8192, nil, time.Millisecond*10)
|
||||
|
||||
trace := make([]int64, b.N*2)
|
||||
for i := 0; i < b.N*2; i++ {
|
||||
trace[i] = getRand(b) % 32768
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
var hit, miss int
|
||||
for i := 0; i < 2*b.N; i++ {
|
||||
if i%2 == 0 {
|
||||
l.Add(trace[i], trace[i])
|
||||
} else {
|
||||
if _, ok := l.Get(trace[i]); ok {
|
||||
hit++
|
||||
} else {
|
||||
miss++
|
||||
}
|
||||
}
|
||||
}
|
||||
b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(hit+miss))
|
||||
}
|
||||
|
||||
func BenchmarkLRU_Freq_WithExpire(b *testing.B) {
|
||||
l := NewLRU[int64, int64](8192, nil, time.Millisecond*10)
|
||||
|
||||
trace := make([]int64, b.N*2)
|
||||
for i := 0; i < b.N*2; i++ {
|
||||
if i%2 == 0 {
|
||||
trace[i] = getRand(b) % 16384
|
||||
} else {
|
||||
trace[i] = getRand(b) % 32768
|
||||
}
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
l.Add(trace[i], trace[i])
|
||||
}
|
||||
var hit, miss int
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, ok := l.Get(trace[i]); ok {
|
||||
hit++
|
||||
} else {
|
||||
miss++
|
||||
}
|
||||
}
|
||||
b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(hit+miss))
|
||||
}
|
||||
|
||||
func TestLRUInterface(_ *testing.T) {
|
||||
var _ simplelru.LRUCache[int, int] = &LRU[int, int]{}
|
||||
}
|
||||
|
||||
func TestLRUNoPurge(t *testing.T) {
|
||||
lc := NewLRU[string, string](10, nil, 0)
|
||||
|
||||
lc.Add("key1", "val1")
|
||||
if lc.Len() != 1 {
|
||||
t.Fatalf("length differs from expected")
|
||||
}
|
||||
|
||||
v, ok := lc.Peek("key1")
|
||||
if v != "val1" {
|
||||
t.Fatalf("value differs from expected")
|
||||
}
|
||||
if !ok {
|
||||
t.Fatalf("should be true")
|
||||
}
|
||||
|
||||
if !lc.Contains("key1") {
|
||||
t.Fatalf("should contain key1")
|
||||
}
|
||||
if lc.Contains("key2") {
|
||||
t.Fatalf("should not contain key2")
|
||||
}
|
||||
|
||||
v, ok = lc.Peek("key2")
|
||||
if v != "" {
|
||||
t.Fatalf("should be empty")
|
||||
}
|
||||
if ok {
|
||||
t.Fatalf("should be false")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(lc.Keys(), []string{"key1"}) {
|
||||
t.Fatalf("value differs from expected")
|
||||
}
|
||||
|
||||
if lc.Resize(0) != 0 {
|
||||
t.Fatalf("evicted count differs from expected")
|
||||
}
|
||||
if lc.Resize(2) != 0 {
|
||||
t.Fatalf("evicted count differs from expected")
|
||||
}
|
||||
lc.Add("key2", "val2")
|
||||
if lc.Resize(1) != 1 {
|
||||
t.Fatalf("evicted count differs from expected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLRUEdgeCases(t *testing.T) {
|
||||
lc := NewLRU[string, *string](2, nil, 0)
|
||||
|
||||
// Adding a nil value
|
||||
lc.Add("key1", nil)
|
||||
|
||||
value, exists := lc.Get("key1")
|
||||
if value != nil || !exists {
|
||||
t.Fatalf("unexpected value or existence flag for key1: value=%v, exists=%v", value, exists)
|
||||
}
|
||||
|
||||
// Adding an entry with the same key but different value
|
||||
newVal := "val1"
|
||||
lc.Add("key1", &newVal)
|
||||
|
||||
value, exists = lc.Get("key1")
|
||||
if value != &newVal || !exists {
|
||||
t.Fatalf("unexpected value or existence flag for key1: value=%v, exists=%v", value, exists)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLRU_Values(t *testing.T) {
|
||||
lc := NewLRU[string, string](3, nil, 0)
|
||||
|
||||
lc.Add("key1", "val1")
|
||||
lc.Add("key2", "val2")
|
||||
lc.Add("key3", "val3")
|
||||
|
||||
values := lc.Values()
|
||||
if !reflect.DeepEqual(values, []string{"val1", "val2", "val3"}) {
|
||||
t.Fatalf("values differs from expected")
|
||||
}
|
||||
}
|
||||
|
||||
// func TestExpirableMultipleClose(_ *testing.T) {
|
||||
// lc := NewLRU[string, string](10, nil, 0)
|
||||
// lc.Close()
|
||||
// // should not panic
|
||||
// lc.Close()
|
||||
// }
|
||||
|
||||
func TestLRUWithPurge(t *testing.T) {
|
||||
var evicted []string
|
||||
lc := NewLRU(10, func(key string, value string) { evicted = append(evicted, key, value) }, 150*time.Millisecond)
|
||||
|
||||
k, v, ok := lc.GetOldest()
|
||||
if k != "" {
|
||||
t.Fatalf("should be empty")
|
||||
}
|
||||
if v != "" {
|
||||
t.Fatalf("should be empty")
|
||||
}
|
||||
if ok {
|
||||
t.Fatalf("should be false")
|
||||
}
|
||||
|
||||
lc.Add("key1", "val1")
|
||||
|
||||
time.Sleep(100 * time.Millisecond) // not enough to expire
|
||||
if lc.Len() != 1 {
|
||||
t.Fatalf("length differs from expected")
|
||||
}
|
||||
|
||||
v, ok = lc.Get("key1")
|
||||
if v != "val1" {
|
||||
t.Fatalf("value differs from expected")
|
||||
}
|
||||
if !ok {
|
||||
t.Fatalf("should be true")
|
||||
}
|
||||
|
||||
time.Sleep(200 * time.Millisecond) // expire
|
||||
v, ok = lc.Get("key1")
|
||||
if ok {
|
||||
t.Fatalf("should be false")
|
||||
}
|
||||
if v != "" {
|
||||
t.Fatalf("should be nil")
|
||||
}
|
||||
|
||||
if lc.Len() != 0 {
|
||||
t.Fatalf("length differs from expected")
|
||||
}
|
||||
if !reflect.DeepEqual(evicted, []string{"key1", "val1"}) {
|
||||
t.Fatalf("value differs from expected")
|
||||
}
|
||||
|
||||
// add new entry
|
||||
lc.Add("key2", "val2")
|
||||
if lc.Len() != 1 {
|
||||
t.Fatalf("length differs from expected")
|
||||
}
|
||||
|
||||
k, v, ok = lc.GetOldest()
|
||||
if k != "key2" {
|
||||
t.Fatalf("value differs from expected")
|
||||
}
|
||||
if v != "val2" {
|
||||
t.Fatalf("value differs from expected")
|
||||
}
|
||||
if !ok {
|
||||
t.Fatalf("should be true")
|
||||
}
|
||||
|
||||
// DeleteExpired, nothing deleted
|
||||
lc.deleteExpired()
|
||||
if lc.Len() != 1 {
|
||||
t.Fatalf("length differs from expected")
|
||||
}
|
||||
if !reflect.DeepEqual(evicted, []string{"key1", "val1"}) {
|
||||
t.Fatalf("value differs from expected")
|
||||
}
|
||||
|
||||
// Purge, cache should be clean
|
||||
lc.Purge()
|
||||
if lc.Len() != 0 {
|
||||
t.Fatalf("length differs from expected")
|
||||
}
|
||||
if !reflect.DeepEqual(evicted, []string{"key1", "val1", "key2", "val2"}) {
|
||||
t.Fatalf("value differs from expected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLRUWithPurgeEnforcedBySize(t *testing.T) {
|
||||
lc := NewLRU[string, string](10, nil, time.Hour)
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
i := i
|
||||
lc.Add(fmt.Sprintf("key%d", i), fmt.Sprintf("val%d", i))
|
||||
v, ok := lc.Get(fmt.Sprintf("key%d", i))
|
||||
if v != fmt.Sprintf("val%d", i) {
|
||||
t.Fatalf("value differs from expected")
|
||||
}
|
||||
if !ok {
|
||||
t.Fatalf("should be true")
|
||||
}
|
||||
if lc.Len() > 20 {
|
||||
t.Fatalf("length should be less than 20")
|
||||
}
|
||||
}
|
||||
|
||||
if lc.Len() != 10 {
|
||||
t.Fatalf("length differs from expected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLRUConcurrency(t *testing.T) {
|
||||
lc := NewLRU[string, string](0, nil, 0)
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(1000)
|
||||
for i := 0; i < 1000; i++ {
|
||||
go func(i int) {
|
||||
lc.Add(fmt.Sprintf("key-%d", i/10), fmt.Sprintf("val-%d", i/10))
|
||||
wg.Done()
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
if lc.Len() != 100 {
|
||||
t.Fatalf("length differs from expected")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLRUInvalidateAndEvict(t *testing.T) {
|
||||
var evicted int
|
||||
lc := NewLRU(-1, func(_, _ string) { evicted++ }, 0)
|
||||
|
||||
lc.Add("key1", "val1")
|
||||
lc.Add("key2", "val2")
|
||||
|
||||
val, ok := lc.Get("key1")
|
||||
if !ok {
|
||||
t.Fatalf("should be true")
|
||||
}
|
||||
if val != "val1" {
|
||||
t.Fatalf("value differs from expected")
|
||||
}
|
||||
if evicted != 0 {
|
||||
t.Fatalf("value differs from expected")
|
||||
}
|
||||
|
||||
lc.Remove("key1")
|
||||
if evicted != 1 {
|
||||
t.Fatalf("value differs from expected")
|
||||
}
|
||||
val, ok = lc.Get("key1")
|
||||
if val != "" {
|
||||
t.Fatalf("should be empty")
|
||||
}
|
||||
if ok {
|
||||
t.Fatalf("should be false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadingExpired(t *testing.T) {
|
||||
lc := NewLRU[string, string](0, nil, time.Millisecond*5)
|
||||
|
||||
lc.Add("key1", "val1")
|
||||
if lc.Len() != 1 {
|
||||
t.Fatalf("length differs from expected")
|
||||
}
|
||||
|
||||
v, ok := lc.Peek("key1")
|
||||
if v != "val1" {
|
||||
t.Fatalf("value differs from expected")
|
||||
}
|
||||
if !ok {
|
||||
t.Fatalf("should be true")
|
||||
}
|
||||
|
||||
v, ok = lc.Get("key1")
|
||||
if v != "val1" {
|
||||
t.Fatalf("value differs from expected")
|
||||
}
|
||||
if !ok {
|
||||
t.Fatalf("should be true")
|
||||
}
|
||||
|
||||
for {
|
||||
result, ok := lc.Get("key1")
|
||||
if ok && result == "" {
|
||||
t.Fatalf("ok should return a result")
|
||||
}
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(time.Millisecond * 100) // wait for expiration reaper
|
||||
if lc.Len() != 0 {
|
||||
t.Fatalf("length differs from expected")
|
||||
}
|
||||
|
||||
v, ok = lc.Peek("key1")
|
||||
if v != "" {
|
||||
t.Fatalf("should be empty")
|
||||
}
|
||||
if ok {
|
||||
t.Fatalf("should be false")
|
||||
}
|
||||
|
||||
v, ok = lc.Get("key1")
|
||||
if v != "" {
|
||||
t.Fatalf("should be empty")
|
||||
}
|
||||
if ok {
|
||||
t.Fatalf("should be false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLRURemoveOldest(t *testing.T) {
|
||||
lc := NewLRU[string, string](2, nil, 0)
|
||||
|
||||
k, v, ok := lc.RemoveOldest()
|
||||
if k != "" {
|
||||
t.Fatalf("should be empty")
|
||||
}
|
||||
if v != "" {
|
||||
t.Fatalf("should be empty")
|
||||
}
|
||||
if ok {
|
||||
t.Fatalf("should be false")
|
||||
}
|
||||
|
||||
ok = lc.Remove("non_existent")
|
||||
if ok {
|
||||
t.Fatalf("should be false")
|
||||
}
|
||||
|
||||
lc.Add("key1", "val1")
|
||||
if lc.Len() != 1 {
|
||||
t.Fatalf("length differs from expected")
|
||||
}
|
||||
|
||||
v, ok = lc.Get("key1")
|
||||
if !ok {
|
||||
t.Fatalf("should be true")
|
||||
}
|
||||
if v != "val1" {
|
||||
t.Fatalf("value differs from expected")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(lc.Keys(), []string{"key1"}) {
|
||||
t.Fatalf("value differs from expected")
|
||||
}
|
||||
if lc.Len() != 1 {
|
||||
t.Fatalf("length differs from expected")
|
||||
}
|
||||
|
||||
lc.Add("key2", "val2")
|
||||
if !reflect.DeepEqual(lc.Keys(), []string{"key1", "key2"}) {
|
||||
t.Fatalf("value differs from expected")
|
||||
}
|
||||
if lc.Len() != 2 {
|
||||
t.Fatalf("length differs from expected")
|
||||
}
|
||||
|
||||
k, v, ok = lc.RemoveOldest()
|
||||
if k != "key1" {
|
||||
t.Fatalf("value differs from expected")
|
||||
}
|
||||
if v != "val1" {
|
||||
t.Fatalf("value differs from expected")
|
||||
}
|
||||
if !ok {
|
||||
t.Fatalf("should be true")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(lc.Keys(), []string{"key2"}) {
|
||||
t.Fatalf("value differs from expected")
|
||||
}
|
||||
if lc.Len() != 1 {
|
||||
t.Fatalf("length differs from expected")
|
||||
}
|
||||
}
|
||||
|
||||
func ExampleLRU() {
|
||||
// make cache with 10ms TTL and 5 max keys
|
||||
cache := NewLRU[string, string](5, nil, time.Millisecond*10)
|
||||
|
||||
// set value under key1.
|
||||
cache.Add("key1", "val1")
|
||||
|
||||
// get value under key1
|
||||
r, ok := cache.Get("key1")
|
||||
|
||||
// check for OK value
|
||||
if ok {
|
||||
fmt.Printf("value before expiration is found: %v, value: %q\n", ok, r)
|
||||
}
|
||||
|
||||
// wait for cache to expire
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
|
||||
// get value under key1 after key expiration
|
||||
r, ok = cache.Get("key1")
|
||||
fmt.Printf("value after expiration is found: %v, value: %q\n", ok, r)
|
||||
|
||||
// set value under key2, would evict old entry because it is already expired.
|
||||
cache.Add("key2", "val2")
|
||||
|
||||
fmt.Printf("Cache len: %d\n", cache.Len())
|
||||
// Output:
|
||||
// value before expiration is found: true, value: "val1"
|
||||
// value after expiration is found: false, value: ""
|
||||
// Cache len: 1
|
||||
}
|
||||
|
||||
func getRand(tb testing.TB) int64 {
|
||||
out, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64))
|
||||
if err != nil {
|
||||
tb.Fatal(err)
|
||||
}
|
||||
return out.Int64()
|
||||
}
|
||||
|
||||
func (c *LRU[K, V]) wantKeys(t *testing.T, want []K) {
|
||||
t.Helper()
|
||||
got := c.Keys()
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("wrong keys got: %v, want: %v ", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCache_EvictionSameKey(t *testing.T) {
|
||||
var evictedKeys []int
|
||||
|
||||
cache := NewLRU[int, struct{}](
|
||||
2,
|
||||
func(key int, _ struct{}) {
|
||||
evictedKeys = append(evictedKeys, key)
|
||||
},
|
||||
0)
|
||||
|
||||
if evicted := cache.Add(1, struct{}{}); evicted {
|
||||
t.Error("First 1: got unexpected eviction")
|
||||
}
|
||||
cache.wantKeys(t, []int{1})
|
||||
|
||||
if evicted := cache.Add(2, struct{}{}); evicted {
|
||||
t.Error("2: got unexpected eviction")
|
||||
}
|
||||
cache.wantKeys(t, []int{1, 2})
|
||||
|
||||
if evicted := cache.Add(1, struct{}{}); evicted {
|
||||
t.Error("Second 1: got unexpected eviction")
|
||||
}
|
||||
cache.wantKeys(t, []int{2, 1})
|
||||
|
||||
if evicted := cache.Add(3, struct{}{}); !evicted {
|
||||
t.Error("3: did not get expected eviction")
|
||||
}
|
||||
cache.wantKeys(t, []int{1, 3})
|
||||
|
||||
want := []int{2}
|
||||
if !reflect.DeepEqual(evictedKeys, want) {
|
||||
t.Errorf("evictedKeys got: %v want: %v", evictedKeys, want)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
module github.com/hashicorp/golang-lru/v2
|
||||
|
||||
go 1.18
|
||||
|
|
@ -1,142 +0,0 @@
|
|||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE_list file.
|
||||
|
||||
package internal
|
||||
|
||||
import "time"
|
||||
|
||||
// Entry is an LRU Entry
|
||||
type Entry[K comparable, V any] struct {
|
||||
// Next and previous pointers in the doubly-linked list of elements.
|
||||
// To simplify the implementation, internally a list l is implemented
|
||||
// as a ring, such that &l.root is both the next element of the last
|
||||
// list element (l.Back()) and the previous element of the first list
|
||||
// element (l.Front()).
|
||||
next, prev *Entry[K, V]
|
||||
|
||||
// The list to which this element belongs.
|
||||
list *LruList[K, V]
|
||||
|
||||
// The LRU Key of this element.
|
||||
Key K
|
||||
|
||||
// The Value stored with this element.
|
||||
Value V
|
||||
|
||||
// The time this element would be cleaned up, optional
|
||||
ExpiresAt time.Time
|
||||
|
||||
// The expiry bucket item was put in, optional
|
||||
ExpireBucket uint8
|
||||
}
|
||||
|
||||
// PrevEntry returns the previous list element or nil.
|
||||
func (e *Entry[K, V]) PrevEntry() *Entry[K, V] {
|
||||
if p := e.prev; e.list != nil && p != &e.list.root {
|
||||
return p
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LruList represents a doubly linked list.
|
||||
// The zero Value for LruList is an empty list ready to use.
|
||||
type LruList[K comparable, V any] struct {
|
||||
root Entry[K, V] // sentinel list element, only &root, root.prev, and root.next are used
|
||||
len int // current list Length excluding (this) sentinel element
|
||||
}
|
||||
|
||||
// Init initializes or clears list l.
|
||||
func (l *LruList[K, V]) Init() *LruList[K, V] {
|
||||
l.root.next = &l.root
|
||||
l.root.prev = &l.root
|
||||
l.len = 0
|
||||
return l
|
||||
}
|
||||
|
||||
// NewList returns an initialized list.
|
||||
func NewList[K comparable, V any]() *LruList[K, V] { return new(LruList[K, V]).Init() }
|
||||
|
||||
// Length returns the number of elements of list l.
|
||||
// The complexity is O(1).
|
||||
func (l *LruList[K, V]) Length() int { return l.len }
|
||||
|
||||
// Back returns the last element of list l or nil if the list is empty.
|
||||
func (l *LruList[K, V]) Back() *Entry[K, V] {
|
||||
if l.len == 0 {
|
||||
return nil
|
||||
}
|
||||
return l.root.prev
|
||||
}
|
||||
|
||||
// lazyInit lazily initializes a zero List Value.
|
||||
func (l *LruList[K, V]) lazyInit() {
|
||||
if l.root.next == nil {
|
||||
l.Init()
|
||||
}
|
||||
}
|
||||
|
||||
// insert inserts e after at, increments l.len, and returns e.
|
||||
func (l *LruList[K, V]) insert(e, at *Entry[K, V]) *Entry[K, V] {
|
||||
e.prev = at
|
||||
e.next = at.next
|
||||
e.prev.next = e
|
||||
e.next.prev = e
|
||||
e.list = l
|
||||
l.len++
|
||||
return e
|
||||
}
|
||||
|
||||
// insertValue is a convenience wrapper for insert(&Entry{Value: v, ExpiresAt: ExpiresAt}, at).
|
||||
func (l *LruList[K, V]) insertValue(k K, v V, expiresAt time.Time, at *Entry[K, V]) *Entry[K, V] {
|
||||
return l.insert(&Entry[K, V]{Value: v, Key: k, ExpiresAt: expiresAt}, at)
|
||||
}
|
||||
|
||||
// Remove removes e from its list, decrements l.len
|
||||
func (l *LruList[K, V]) Remove(e *Entry[K, V]) V {
|
||||
e.prev.next = e.next
|
||||
e.next.prev = e.prev
|
||||
e.next = nil // avoid memory leaks
|
||||
e.prev = nil // avoid memory leaks
|
||||
e.list = nil
|
||||
l.len--
|
||||
|
||||
return e.Value
|
||||
}
|
||||
|
||||
// move moves e to next to at.
|
||||
func (l *LruList[K, V]) move(e, at *Entry[K, V]) {
|
||||
if e == at {
|
||||
return
|
||||
}
|
||||
e.prev.next = e.next
|
||||
e.next.prev = e.prev
|
||||
|
||||
e.prev = at
|
||||
e.next = at.next
|
||||
e.prev.next = e
|
||||
e.next.prev = e
|
||||
}
|
||||
|
||||
// PushFront inserts a new element e with value v at the front of list l and returns e.
|
||||
func (l *LruList[K, V]) PushFront(k K, v V) *Entry[K, V] {
|
||||
l.lazyInit()
|
||||
return l.insertValue(k, v, time.Time{}, &l.root)
|
||||
}
|
||||
|
||||
// PushFrontExpirable inserts a new expirable element e with Value v at the front of list l and returns e.
|
||||
func (l *LruList[K, V]) PushFrontExpirable(k K, v V, expiresAt time.Time) *Entry[K, V] {
|
||||
l.lazyInit()
|
||||
return l.insertValue(k, v, expiresAt, &l.root)
|
||||
}
|
||||
|
||||
// MoveToFront moves element e to the front of list l.
|
||||
// If e is not an element of l, the list is not modified.
|
||||
// The element must not be nil.
|
||||
func (l *LruList[K, V]) MoveToFront(e *Entry[K, V]) {
|
||||
if e.list != l || l.root.next == e {
|
||||
return
|
||||
}
|
||||
// see comment in List.Remove about initialization of l
|
||||
l.move(e, &l.root)
|
||||
}
|
||||
|
|
@ -1,250 +0,0 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package lru
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/golang-lru/v2/simplelru"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultEvictedBufferSize defines the default buffer size to store evicted key/val
|
||||
DefaultEvictedBufferSize = 16
|
||||
)
|
||||
|
||||
// Cache is a thread-safe fixed size LRU cache.
|
||||
type Cache[K comparable, V any] struct {
|
||||
lru *simplelru.LRU[K, V]
|
||||
evictedKeys []K
|
||||
evictedVals []V
|
||||
onEvictedCB func(k K, v V)
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// New creates an LRU of the given size.
|
||||
func New[K comparable, V any](size int) (*Cache[K, V], error) {
|
||||
return NewWithEvict[K, V](size, nil)
|
||||
}
|
||||
|
||||
// NewWithEvict constructs a fixed size cache with the given eviction
|
||||
// callback.
|
||||
func NewWithEvict[K comparable, V any](size int, onEvicted func(key K, value V)) (c *Cache[K, V], err error) {
|
||||
// create a cache with default settings
|
||||
c = &Cache[K, V]{
|
||||
onEvictedCB: onEvicted,
|
||||
}
|
||||
if onEvicted != nil {
|
||||
c.initEvictBuffers()
|
||||
onEvicted = c.onEvicted
|
||||
}
|
||||
c.lru, err = simplelru.NewLRU(size, onEvicted)
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Cache[K, V]) initEvictBuffers() {
|
||||
c.evictedKeys = make([]K, 0, DefaultEvictedBufferSize)
|
||||
c.evictedVals = make([]V, 0, DefaultEvictedBufferSize)
|
||||
}
|
||||
|
||||
// onEvicted save evicted key/val and sent in externally registered callback
|
||||
// outside of critical section
|
||||
func (c *Cache[K, V]) onEvicted(k K, v V) {
|
||||
c.evictedKeys = append(c.evictedKeys, k)
|
||||
c.evictedVals = append(c.evictedVals, v)
|
||||
}
|
||||
|
||||
// Purge is used to completely clear the cache.
|
||||
func (c *Cache[K, V]) Purge() {
|
||||
var ks []K
|
||||
var vs []V
|
||||
c.lock.Lock()
|
||||
c.lru.Purge()
|
||||
if c.onEvictedCB != nil && len(c.evictedKeys) > 0 {
|
||||
ks, vs = c.evictedKeys, c.evictedVals
|
||||
c.initEvictBuffers()
|
||||
}
|
||||
c.lock.Unlock()
|
||||
// invoke callback outside of critical section
|
||||
if c.onEvictedCB != nil {
|
||||
for i := 0; i < len(ks); i++ {
|
||||
c.onEvictedCB(ks[i], vs[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add adds a value to the cache. Returns true if an eviction occurred.
|
||||
func (c *Cache[K, V]) Add(key K, value V) (evicted bool) {
|
||||
var k K
|
||||
var v V
|
||||
c.lock.Lock()
|
||||
evicted = c.lru.Add(key, value)
|
||||
if c.onEvictedCB != nil && evicted {
|
||||
k, v = c.evictedKeys[0], c.evictedVals[0]
|
||||
c.evictedKeys, c.evictedVals = c.evictedKeys[:0], c.evictedVals[:0]
|
||||
}
|
||||
c.lock.Unlock()
|
||||
if c.onEvictedCB != nil && evicted {
|
||||
c.onEvictedCB(k, v)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Get looks up a key's value from the cache.
|
||||
func (c *Cache[K, V]) Get(key K) (value V, ok bool) {
|
||||
c.lock.Lock()
|
||||
value, ok = c.lru.Get(key)
|
||||
c.lock.Unlock()
|
||||
return value, ok
|
||||
}
|
||||
|
||||
// Contains checks if a key is in the cache, without updating the
|
||||
// recent-ness or deleting it for being stale.
|
||||
func (c *Cache[K, V]) Contains(key K) bool {
|
||||
c.lock.RLock()
|
||||
containKey := c.lru.Contains(key)
|
||||
c.lock.RUnlock()
|
||||
return containKey
|
||||
}
|
||||
|
||||
// Peek returns the key value (or undefined if not found) without updating
|
||||
// the "recently used"-ness of the key.
|
||||
func (c *Cache[K, V]) Peek(key K) (value V, ok bool) {
|
||||
c.lock.RLock()
|
||||
value, ok = c.lru.Peek(key)
|
||||
c.lock.RUnlock()
|
||||
return value, ok
|
||||
}
|
||||
|
||||
// ContainsOrAdd checks if a key is in the cache without updating the
|
||||
// recent-ness or deleting it for being stale, and if not, adds the value.
|
||||
// Returns whether found and whether an eviction occurred.
|
||||
func (c *Cache[K, V]) ContainsOrAdd(key K, value V) (ok, evicted bool) {
|
||||
var k K
|
||||
var v V
|
||||
c.lock.Lock()
|
||||
if c.lru.Contains(key) {
|
||||
c.lock.Unlock()
|
||||
return true, false
|
||||
}
|
||||
evicted = c.lru.Add(key, value)
|
||||
if c.onEvictedCB != nil && evicted {
|
||||
k, v = c.evictedKeys[0], c.evictedVals[0]
|
||||
c.evictedKeys, c.evictedVals = c.evictedKeys[:0], c.evictedVals[:0]
|
||||
}
|
||||
c.lock.Unlock()
|
||||
if c.onEvictedCB != nil && evicted {
|
||||
c.onEvictedCB(k, v)
|
||||
}
|
||||
return false, evicted
|
||||
}
|
||||
|
||||
// PeekOrAdd checks if a key is in the cache without updating the
|
||||
// recent-ness or deleting it for being stale, and if not, adds the value.
|
||||
// Returns whether found and whether an eviction occurred.
|
||||
func (c *Cache[K, V]) PeekOrAdd(key K, value V) (previous V, ok, evicted bool) {
|
||||
var k K
|
||||
var v V
|
||||
c.lock.Lock()
|
||||
previous, ok = c.lru.Peek(key)
|
||||
if ok {
|
||||
c.lock.Unlock()
|
||||
return previous, true, false
|
||||
}
|
||||
evicted = c.lru.Add(key, value)
|
||||
if c.onEvictedCB != nil && evicted {
|
||||
k, v = c.evictedKeys[0], c.evictedVals[0]
|
||||
c.evictedKeys, c.evictedVals = c.evictedKeys[:0], c.evictedVals[:0]
|
||||
}
|
||||
c.lock.Unlock()
|
||||
if c.onEvictedCB != nil && evicted {
|
||||
c.onEvictedCB(k, v)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Remove removes the provided key from the cache.
|
||||
func (c *Cache[K, V]) Remove(key K) (present bool) {
|
||||
var k K
|
||||
var v V
|
||||
c.lock.Lock()
|
||||
present = c.lru.Remove(key)
|
||||
if c.onEvictedCB != nil && present {
|
||||
k, v = c.evictedKeys[0], c.evictedVals[0]
|
||||
c.evictedKeys, c.evictedVals = c.evictedKeys[:0], c.evictedVals[:0]
|
||||
}
|
||||
c.lock.Unlock()
|
||||
if c.onEvictedCB != nil && present {
|
||||
c.onEvictedCB(k, v)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Resize changes the cache size.
|
||||
func (c *Cache[K, V]) Resize(size int) (evicted int) {
|
||||
var ks []K
|
||||
var vs []V
|
||||
c.lock.Lock()
|
||||
evicted = c.lru.Resize(size)
|
||||
if c.onEvictedCB != nil && evicted > 0 {
|
||||
ks, vs = c.evictedKeys, c.evictedVals
|
||||
c.initEvictBuffers()
|
||||
}
|
||||
c.lock.Unlock()
|
||||
if c.onEvictedCB != nil && evicted > 0 {
|
||||
for i := 0; i < len(ks); i++ {
|
||||
c.onEvictedCB(ks[i], vs[i])
|
||||
}
|
||||
}
|
||||
return evicted
|
||||
}
|
||||
|
||||
// RemoveOldest removes the oldest item from the cache.
|
||||
func (c *Cache[K, V]) RemoveOldest() (key K, value V, ok bool) {
|
||||
var k K
|
||||
var v V
|
||||
c.lock.Lock()
|
||||
key, value, ok = c.lru.RemoveOldest()
|
||||
if c.onEvictedCB != nil && ok {
|
||||
k, v = c.evictedKeys[0], c.evictedVals[0]
|
||||
c.evictedKeys, c.evictedVals = c.evictedKeys[:0], c.evictedVals[:0]
|
||||
}
|
||||
c.lock.Unlock()
|
||||
if c.onEvictedCB != nil && ok {
|
||||
c.onEvictedCB(k, v)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetOldest returns the oldest entry
|
||||
func (c *Cache[K, V]) GetOldest() (key K, value V, ok bool) {
|
||||
c.lock.RLock()
|
||||
key, value, ok = c.lru.GetOldest()
|
||||
c.lock.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
// Keys returns a slice of the keys in the cache, from oldest to newest.
|
||||
func (c *Cache[K, V]) Keys() []K {
|
||||
c.lock.RLock()
|
||||
keys := c.lru.Keys()
|
||||
c.lock.RUnlock()
|
||||
return keys
|
||||
}
|
||||
|
||||
// Values returns a slice of the values in the cache, from oldest to newest.
|
||||
func (c *Cache[K, V]) Values() []V {
|
||||
c.lock.RLock()
|
||||
values := c.lru.Values()
|
||||
c.lock.RUnlock()
|
||||
return values
|
||||
}
|
||||
|
||||
// Len returns the number of items in the cache.
|
||||
func (c *Cache[K, V]) Len() int {
|
||||
c.lock.RLock()
|
||||
length := c.lru.Len()
|
||||
c.lock.RUnlock()
|
||||
return length
|
||||
}
|
||||
|
|
@ -1,443 +0,0 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package lru
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkLRU_Rand(b *testing.B) {
|
||||
l, err := New[int64, int64](8192)
|
||||
if err != nil {
|
||||
b.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
trace := make([]int64, b.N*2)
|
||||
for i := 0; i < b.N*2; i++ {
|
||||
trace[i] = getRand(b) % 32768
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
var hit, miss int
|
||||
for i := 0; i < 2*b.N; i++ {
|
||||
if i%2 == 0 {
|
||||
l.Add(trace[i], trace[i])
|
||||
} else {
|
||||
if _, ok := l.Get(trace[i]); ok {
|
||||
hit++
|
||||
} else {
|
||||
miss++
|
||||
}
|
||||
}
|
||||
}
|
||||
b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(hit+miss))
|
||||
}
|
||||
|
||||
func BenchmarkLRU_Freq(b *testing.B) {
|
||||
l, err := New[int64, int64](8192)
|
||||
if err != nil {
|
||||
b.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
trace := make([]int64, b.N*2)
|
||||
for i := 0; i < b.N*2; i++ {
|
||||
if i%2 == 0 {
|
||||
trace[i] = getRand(b) % 16384
|
||||
} else {
|
||||
trace[i] = getRand(b) % 32768
|
||||
}
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
l.Add(trace[i], trace[i])
|
||||
}
|
||||
var hit, miss int
|
||||
for i := 0; i < b.N; i++ {
|
||||
if _, ok := l.Get(trace[i]); ok {
|
||||
hit++
|
||||
} else {
|
||||
miss++
|
||||
}
|
||||
}
|
||||
b.Logf("hit: %d miss: %d ratio: %f", hit, miss, float64(hit)/float64(hit+miss))
|
||||
}
|
||||
|
||||
func TestLRU(t *testing.T) {
|
||||
evictCounter := 0
|
||||
onEvicted := func(k int, v int) {
|
||||
if k != v {
|
||||
t.Fatalf("Evict values not equal (%v!=%v)", k, v)
|
||||
}
|
||||
evictCounter++
|
||||
}
|
||||
l, err := NewWithEvict(128, onEvicted)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
for i := 0; i < 256; i++ {
|
||||
l.Add(i, i)
|
||||
}
|
||||
if l.Len() != 128 {
|
||||
t.Fatalf("bad len: %v", l.Len())
|
||||
}
|
||||
|
||||
if evictCounter != 128 {
|
||||
t.Fatalf("bad evict count: %v", evictCounter)
|
||||
}
|
||||
|
||||
for i, k := range l.Keys() {
|
||||
if v, ok := l.Get(k); !ok || v != k || v != i+128 {
|
||||
t.Fatalf("bad key: %v", k)
|
||||
}
|
||||
}
|
||||
for i, v := range l.Values() {
|
||||
if v != i+128 {
|
||||
t.Fatalf("bad value: %v", v)
|
||||
}
|
||||
}
|
||||
for i := 0; i < 128; i++ {
|
||||
if _, ok := l.Get(i); ok {
|
||||
t.Fatalf("should be evicted")
|
||||
}
|
||||
}
|
||||
for i := 128; i < 256; i++ {
|
||||
if _, ok := l.Get(i); !ok {
|
||||
t.Fatalf("should not be evicted")
|
||||
}
|
||||
}
|
||||
for i := 128; i < 192; i++ {
|
||||
l.Remove(i)
|
||||
if _, ok := l.Get(i); ok {
|
||||
t.Fatalf("should be deleted")
|
||||
}
|
||||
}
|
||||
|
||||
l.Get(192) // expect 192 to be last key in l.Keys()
|
||||
|
||||
for i, k := range l.Keys() {
|
||||
if (i < 63 && k != i+193) || (i == 63 && k != 192) {
|
||||
t.Fatalf("out of order key: %v", k)
|
||||
}
|
||||
}
|
||||
|
||||
l.Purge()
|
||||
if l.Len() != 0 {
|
||||
t.Fatalf("bad len: %v", l.Len())
|
||||
}
|
||||
if _, ok := l.Get(200); ok {
|
||||
t.Fatalf("should contain nothing")
|
||||
}
|
||||
}
|
||||
|
||||
// test that Add returns true/false if an eviction occurred
|
||||
func TestLRUAdd(t *testing.T) {
|
||||
evictCounter := 0
|
||||
onEvicted := func(k int, v int) {
|
||||
evictCounter++
|
||||
}
|
||||
|
||||
l, err := NewWithEvict(1, onEvicted)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
if l.Add(1, 1) == true || evictCounter != 0 {
|
||||
t.Errorf("should not have an eviction")
|
||||
}
|
||||
if l.Add(2, 2) == false || evictCounter != 1 {
|
||||
t.Errorf("should have an eviction")
|
||||
}
|
||||
}
|
||||
|
||||
// test that Contains doesn't update recent-ness
|
||||
func TestLRUContains(t *testing.T) {
|
||||
l, err := New[int, int](2)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
l.Add(1, 1)
|
||||
l.Add(2, 2)
|
||||
if !l.Contains(1) {
|
||||
t.Errorf("1 should be contained")
|
||||
}
|
||||
|
||||
l.Add(3, 3)
|
||||
if l.Contains(1) {
|
||||
t.Errorf("Contains should not have updated recent-ness of 1")
|
||||
}
|
||||
}
|
||||
|
||||
// test that ContainsOrAdd doesn't update recent-ness
|
||||
func TestLRUContainsOrAdd(t *testing.T) {
|
||||
l, err := New[int, int](2)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
l.Add(1, 1)
|
||||
l.Add(2, 2)
|
||||
contains, evict := l.ContainsOrAdd(1, 1)
|
||||
if !contains {
|
||||
t.Errorf("1 should be contained")
|
||||
}
|
||||
if evict {
|
||||
t.Errorf("nothing should be evicted here")
|
||||
}
|
||||
|
||||
l.Add(3, 3)
|
||||
contains, evict = l.ContainsOrAdd(1, 1)
|
||||
if contains {
|
||||
t.Errorf("1 should not have been contained")
|
||||
}
|
||||
if !evict {
|
||||
t.Errorf("an eviction should have occurred")
|
||||
}
|
||||
if !l.Contains(1) {
|
||||
t.Errorf("now 1 should be contained")
|
||||
}
|
||||
}
|
||||
|
||||
// test that PeekOrAdd doesn't update recent-ness
|
||||
func TestLRUPeekOrAdd(t *testing.T) {
|
||||
l, err := New[int, int](2)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
l.Add(1, 1)
|
||||
l.Add(2, 2)
|
||||
previous, contains, evict := l.PeekOrAdd(1, 1)
|
||||
if !contains {
|
||||
t.Errorf("1 should be contained")
|
||||
}
|
||||
if evict {
|
||||
t.Errorf("nothing should be evicted here")
|
||||
}
|
||||
if previous != 1 {
|
||||
t.Errorf("previous is not equal to 1")
|
||||
}
|
||||
|
||||
l.Add(3, 3)
|
||||
contains, evict = l.ContainsOrAdd(1, 1)
|
||||
if contains {
|
||||
t.Errorf("1 should not have been contained")
|
||||
}
|
||||
if !evict {
|
||||
t.Errorf("an eviction should have occurred")
|
||||
}
|
||||
if !l.Contains(1) {
|
||||
t.Errorf("now 1 should be contained")
|
||||
}
|
||||
}
|
||||
|
||||
// test that Peek doesn't update recent-ness
|
||||
func TestLRUPeek(t *testing.T) {
|
||||
l, err := New[int, int](2)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
l.Add(1, 1)
|
||||
l.Add(2, 2)
|
||||
if v, ok := l.Peek(1); !ok || v != 1 {
|
||||
t.Errorf("1 should be set to 1: %v, %v", v, ok)
|
||||
}
|
||||
|
||||
l.Add(3, 3)
|
||||
if l.Contains(1) {
|
||||
t.Errorf("should not have updated recent-ness of 1")
|
||||
}
|
||||
}
|
||||
|
||||
// test that Resize can upsize and downsize
|
||||
func TestLRUResize(t *testing.T) {
|
||||
onEvictCounter := 0
|
||||
onEvicted := func(k int, v int) {
|
||||
onEvictCounter++
|
||||
}
|
||||
l, err := NewWithEvict(2, onEvicted)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Downsize
|
||||
l.Add(1, 1)
|
||||
l.Add(2, 2)
|
||||
evicted := l.Resize(1)
|
||||
if evicted != 1 {
|
||||
t.Errorf("1 element should have been evicted: %v", evicted)
|
||||
}
|
||||
if onEvictCounter != 1 {
|
||||
t.Errorf("onEvicted should have been called 1 time: %v", onEvictCounter)
|
||||
}
|
||||
|
||||
l.Add(3, 3)
|
||||
if l.Contains(1) {
|
||||
t.Errorf("Element 1 should have been evicted")
|
||||
}
|
||||
|
||||
// Upsize
|
||||
evicted = l.Resize(2)
|
||||
if evicted != 0 {
|
||||
t.Errorf("0 elements should have been evicted: %v", evicted)
|
||||
}
|
||||
|
||||
l.Add(4, 4)
|
||||
if !l.Contains(3) || !l.Contains(4) {
|
||||
t.Errorf("Cache should have contained 2 elements")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Cache[K, V]) wantKeys(t *testing.T, want []K) {
|
||||
t.Helper()
|
||||
got := c.Keys()
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("wrong keys got: %v, want: %v ", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCache_EvictionSameKey(t *testing.T) {
|
||||
t.Run("Add", func(t *testing.T) {
|
||||
var evictedKeys []int
|
||||
|
||||
cache, _ := NewWithEvict(
|
||||
2,
|
||||
func(key int, _ struct{}) {
|
||||
evictedKeys = append(evictedKeys, key)
|
||||
})
|
||||
|
||||
if evicted := cache.Add(1, struct{}{}); evicted {
|
||||
t.Error("First 1: got unexpected eviction")
|
||||
}
|
||||
cache.wantKeys(t, []int{1})
|
||||
|
||||
if evicted := cache.Add(2, struct{}{}); evicted {
|
||||
t.Error("2: got unexpected eviction")
|
||||
}
|
||||
cache.wantKeys(t, []int{1, 2})
|
||||
|
||||
if evicted := cache.Add(1, struct{}{}); evicted {
|
||||
t.Error("Second 1: got unexpected eviction")
|
||||
}
|
||||
cache.wantKeys(t, []int{2, 1})
|
||||
|
||||
if evicted := cache.Add(3, struct{}{}); !evicted {
|
||||
t.Error("3: did not get expected eviction")
|
||||
}
|
||||
cache.wantKeys(t, []int{1, 3})
|
||||
|
||||
want := []int{2}
|
||||
if !reflect.DeepEqual(evictedKeys, want) {
|
||||
t.Errorf("evictedKeys got: %v want: %v", evictedKeys, want)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("ContainsOrAdd", func(t *testing.T) {
|
||||
var evictedKeys []int
|
||||
|
||||
cache, _ := NewWithEvict(
|
||||
2,
|
||||
func(key int, _ struct{}) {
|
||||
evictedKeys = append(evictedKeys, key)
|
||||
})
|
||||
|
||||
contained, evicted := cache.ContainsOrAdd(1, struct{}{})
|
||||
if contained {
|
||||
t.Error("First 1: got unexpected contained")
|
||||
}
|
||||
if evicted {
|
||||
t.Error("First 1: got unexpected eviction")
|
||||
}
|
||||
cache.wantKeys(t, []int{1})
|
||||
|
||||
contained, evicted = cache.ContainsOrAdd(2, struct{}{})
|
||||
if contained {
|
||||
t.Error("2: got unexpected contained")
|
||||
}
|
||||
if evicted {
|
||||
t.Error("2: got unexpected eviction")
|
||||
}
|
||||
cache.wantKeys(t, []int{1, 2})
|
||||
|
||||
contained, evicted = cache.ContainsOrAdd(1, struct{}{})
|
||||
if !contained {
|
||||
t.Error("Second 1: did not get expected contained")
|
||||
}
|
||||
if evicted {
|
||||
t.Error("Second 1: got unexpected eviction")
|
||||
}
|
||||
cache.wantKeys(t, []int{1, 2})
|
||||
|
||||
contained, evicted = cache.ContainsOrAdd(3, struct{}{})
|
||||
if contained {
|
||||
t.Error("3: got unexpected contained")
|
||||
}
|
||||
if !evicted {
|
||||
t.Error("3: did not get expected eviction")
|
||||
}
|
||||
cache.wantKeys(t, []int{2, 3})
|
||||
|
||||
want := []int{1}
|
||||
if !reflect.DeepEqual(evictedKeys, want) {
|
||||
t.Errorf("evictedKeys got: %v want: %v", evictedKeys, want)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("PeekOrAdd", func(t *testing.T) {
|
||||
var evictedKeys []int
|
||||
|
||||
cache, _ := NewWithEvict(
|
||||
2,
|
||||
func(key int, _ struct{}) {
|
||||
evictedKeys = append(evictedKeys, key)
|
||||
})
|
||||
|
||||
_, contained, evicted := cache.PeekOrAdd(1, struct{}{})
|
||||
if contained {
|
||||
t.Error("First 1: got unexpected contained")
|
||||
}
|
||||
if evicted {
|
||||
t.Error("First 1: got unexpected eviction")
|
||||
}
|
||||
cache.wantKeys(t, []int{1})
|
||||
|
||||
_, contained, evicted = cache.PeekOrAdd(2, struct{}{})
|
||||
if contained {
|
||||
t.Error("2: got unexpected contained")
|
||||
}
|
||||
if evicted {
|
||||
t.Error("2: got unexpected eviction")
|
||||
}
|
||||
cache.wantKeys(t, []int{1, 2})
|
||||
|
||||
_, contained, evicted = cache.PeekOrAdd(1, struct{}{})
|
||||
if !contained {
|
||||
t.Error("Second 1: did not get expected contained")
|
||||
}
|
||||
if evicted {
|
||||
t.Error("Second 1: got unexpected eviction")
|
||||
}
|
||||
cache.wantKeys(t, []int{1, 2})
|
||||
|
||||
_, contained, evicted = cache.PeekOrAdd(3, struct{}{})
|
||||
if contained {
|
||||
t.Error("3: got unexpected contained")
|
||||
}
|
||||
if !evicted {
|
||||
t.Error("3: did not get expected eviction")
|
||||
}
|
||||
cache.wantKeys(t, []int{2, 3})
|
||||
|
||||
want := []int{1}
|
||||
if !reflect.DeepEqual(evictedKeys, want) {
|
||||
t.Errorf("evictedKeys got: %v want: %v", evictedKeys, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
This license applies to simplelru/list.go
|
||||
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
@ -1,177 +0,0 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package simplelru
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/hashicorp/golang-lru/v2/internal"
|
||||
)
|
||||
|
||||
// EvictCallback is used to get a callback when a cache entry is evicted
|
||||
type EvictCallback[K comparable, V any] func(key K, value V)
|
||||
|
||||
// LRU implements a non-thread safe fixed size LRU cache
|
||||
type LRU[K comparable, V any] struct {
|
||||
size int
|
||||
evictList *internal.LruList[K, V]
|
||||
items map[K]*internal.Entry[K, V]
|
||||
onEvict EvictCallback[K, V]
|
||||
}
|
||||
|
||||
// NewLRU constructs an LRU of the given size
|
||||
func NewLRU[K comparable, V any](size int, onEvict EvictCallback[K, V]) (*LRU[K, V], error) {
|
||||
if size <= 0 {
|
||||
return nil, errors.New("must provide a positive size")
|
||||
}
|
||||
|
||||
c := &LRU[K, V]{
|
||||
size: size,
|
||||
evictList: internal.NewList[K, V](),
|
||||
items: make(map[K]*internal.Entry[K, V]),
|
||||
onEvict: onEvict,
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Purge is used to completely clear the cache.
|
||||
func (c *LRU[K, V]) Purge() {
|
||||
for k, v := range c.items {
|
||||
if c.onEvict != nil {
|
||||
c.onEvict(k, v.Value)
|
||||
}
|
||||
delete(c.items, k)
|
||||
}
|
||||
c.evictList.Init()
|
||||
}
|
||||
|
||||
// Add adds a value to the cache. Returns true if an eviction occurred.
|
||||
func (c *LRU[K, V]) Add(key K, value V) (evicted bool) {
|
||||
// Check for existing item
|
||||
if ent, ok := c.items[key]; ok {
|
||||
c.evictList.MoveToFront(ent)
|
||||
ent.Value = value
|
||||
return false
|
||||
}
|
||||
|
||||
// Add new item
|
||||
ent := c.evictList.PushFront(key, value)
|
||||
c.items[key] = ent
|
||||
|
||||
evict := c.evictList.Length() > c.size
|
||||
// Verify size not exceeded
|
||||
if evict {
|
||||
c.removeOldest()
|
||||
}
|
||||
return evict
|
||||
}
|
||||
|
||||
// Get looks up a key's value from the cache.
|
||||
func (c *LRU[K, V]) Get(key K) (value V, ok bool) {
|
||||
if ent, ok := c.items[key]; ok {
|
||||
c.evictList.MoveToFront(ent)
|
||||
return ent.Value, true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Contains checks if a key is in the cache, without updating the recent-ness
|
||||
// or deleting it for being stale.
|
||||
func (c *LRU[K, V]) Contains(key K) (ok bool) {
|
||||
_, ok = c.items[key]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Peek returns the key value (or undefined if not found) without updating
|
||||
// the "recently used"-ness of the key.
|
||||
func (c *LRU[K, V]) Peek(key K) (value V, ok bool) {
|
||||
var ent *internal.Entry[K, V]
|
||||
if ent, ok = c.items[key]; ok {
|
||||
return ent.Value, true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Remove removes the provided key from the cache, returning if the
|
||||
// key was contained.
|
||||
func (c *LRU[K, V]) Remove(key K) (present bool) {
|
||||
if ent, ok := c.items[key]; ok {
|
||||
c.removeElement(ent)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RemoveOldest removes the oldest item from the cache.
|
||||
func (c *LRU[K, V]) RemoveOldest() (key K, value V, ok bool) {
|
||||
if ent := c.evictList.Back(); ent != nil {
|
||||
c.removeElement(ent)
|
||||
return ent.Key, ent.Value, true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GetOldest returns the oldest entry
|
||||
func (c *LRU[K, V]) GetOldest() (key K, value V, ok bool) {
|
||||
if ent := c.evictList.Back(); ent != nil {
|
||||
return ent.Key, ent.Value, true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Keys returns a slice of the keys in the cache, from oldest to newest.
|
||||
func (c *LRU[K, V]) Keys() []K {
|
||||
keys := make([]K, c.evictList.Length())
|
||||
i := 0
|
||||
for ent := c.evictList.Back(); ent != nil; ent = ent.PrevEntry() {
|
||||
keys[i] = ent.Key
|
||||
i++
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
// Values returns a slice of the values in the cache, from oldest to newest.
|
||||
func (c *LRU[K, V]) Values() []V {
|
||||
values := make([]V, len(c.items))
|
||||
i := 0
|
||||
for ent := c.evictList.Back(); ent != nil; ent = ent.PrevEntry() {
|
||||
values[i] = ent.Value
|
||||
i++
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
// Len returns the number of items in the cache.
|
||||
func (c *LRU[K, V]) Len() int {
|
||||
return c.evictList.Length()
|
||||
}
|
||||
|
||||
// Resize changes the cache size.
|
||||
func (c *LRU[K, V]) Resize(size int) (evicted int) {
|
||||
diff := c.Len() - size
|
||||
if diff < 0 {
|
||||
diff = 0
|
||||
}
|
||||
for i := 0; i < diff; i++ {
|
||||
c.removeOldest()
|
||||
}
|
||||
c.size = size
|
||||
return diff
|
||||
}
|
||||
|
||||
// removeOldest removes the oldest item from the cache.
|
||||
func (c *LRU[K, V]) removeOldest() {
|
||||
if ent := c.evictList.Back(); ent != nil {
|
||||
c.removeElement(ent)
|
||||
}
|
||||
}
|
||||
|
||||
// removeElement is used to remove a given list element from the cache
|
||||
func (c *LRU[K, V]) removeElement(e *internal.Entry[K, V]) {
|
||||
c.evictList.Remove(e)
|
||||
delete(c.items, e.Key)
|
||||
if c.onEvict != nil {
|
||||
c.onEvict(e.Key, e.Value)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
// Package simplelru provides simple LRU implementation based on build-in container/list.
|
||||
package simplelru
|
||||
|
||||
// LRUCache is the interface for simple LRU cache.
|
||||
type LRUCache[K comparable, V any] interface {
|
||||
// Adds a value to the cache, returns true if an eviction occurred and
|
||||
// updates the "recently used"-ness of the key.
|
||||
Add(key K, value V) bool
|
||||
|
||||
// Returns key's value from the cache and
|
||||
// updates the "recently used"-ness of the key. #value, isFound
|
||||
Get(key K) (value V, ok bool)
|
||||
|
||||
// Checks if a key exists in cache without updating the recent-ness.
|
||||
Contains(key K) (ok bool)
|
||||
|
||||
// Returns key's value without updating the "recently used"-ness of the key.
|
||||
Peek(key K) (value V, ok bool)
|
||||
|
||||
// Removes a key from the cache.
|
||||
Remove(key K) bool
|
||||
|
||||
// Removes the oldest entry from cache.
|
||||
RemoveOldest() (K, V, bool)
|
||||
|
||||
// Returns the oldest entry from the cache. #key, value, isFound
|
||||
GetOldest() (K, V, bool)
|
||||
|
||||
// Returns a slice of the keys in the cache, from oldest to newest.
|
||||
Keys() []K
|
||||
|
||||
// Values returns a slice of the values in the cache, from oldest to newest.
|
||||
Values() []V
|
||||
|
||||
// Returns the number of items in the cache.
|
||||
Len() int
|
||||
|
||||
// Clears all cache entries.
|
||||
Purge()
|
||||
|
||||
// Resizes cache, returning number evicted
|
||||
Resize(int) int
|
||||
}
|
||||
|
|
@ -1,255 +0,0 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package simplelru
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLRU(t *testing.T) {
|
||||
evictCounter := 0
|
||||
onEvicted := func(k int, v int) {
|
||||
if k != v {
|
||||
t.Fatalf("Evict values not equal (%v!=%v)", k, v)
|
||||
}
|
||||
evictCounter++
|
||||
}
|
||||
l, err := NewLRU(128, onEvicted)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
for i := 0; i < 256; i++ {
|
||||
l.Add(i, i)
|
||||
}
|
||||
if l.Len() != 128 {
|
||||
t.Fatalf("bad len: %v", l.Len())
|
||||
}
|
||||
|
||||
if evictCounter != 128 {
|
||||
t.Fatalf("bad evict count: %v", evictCounter)
|
||||
}
|
||||
|
||||
for i, k := range l.Keys() {
|
||||
if v, ok := l.Get(k); !ok || v != k || v != i+128 {
|
||||
t.Fatalf("bad key: %v", k)
|
||||
}
|
||||
}
|
||||
for i, v := range l.Values() {
|
||||
if v != i+128 {
|
||||
t.Fatalf("bad value: %v", v)
|
||||
}
|
||||
}
|
||||
for i := 0; i < 128; i++ {
|
||||
if _, ok := l.Get(i); ok {
|
||||
t.Fatalf("should be evicted")
|
||||
}
|
||||
}
|
||||
for i := 128; i < 256; i++ {
|
||||
if _, ok := l.Get(i); !ok {
|
||||
t.Fatalf("should not be evicted")
|
||||
}
|
||||
}
|
||||
for i := 128; i < 192; i++ {
|
||||
if ok := l.Remove(i); !ok {
|
||||
t.Fatalf("should be contained")
|
||||
}
|
||||
if ok := l.Remove(i); ok {
|
||||
t.Fatalf("should not be contained")
|
||||
}
|
||||
if _, ok := l.Get(i); ok {
|
||||
t.Fatalf("should be deleted")
|
||||
}
|
||||
}
|
||||
|
||||
l.Get(192) // expect 192 to be last key in l.Keys()
|
||||
|
||||
for i, k := range l.Keys() {
|
||||
if (i < 63 && k != i+193) || (i == 63 && k != 192) {
|
||||
t.Fatalf("out of order key: %v", k)
|
||||
}
|
||||
}
|
||||
|
||||
l.Purge()
|
||||
if l.Len() != 0 {
|
||||
t.Fatalf("bad len: %v", l.Len())
|
||||
}
|
||||
if _, ok := l.Get(200); ok {
|
||||
t.Fatalf("should contain nothing")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLRU_GetOldest_RemoveOldest(t *testing.T) {
|
||||
l, err := NewLRU[int, int](128, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
for i := 0; i < 256; i++ {
|
||||
l.Add(i, i)
|
||||
}
|
||||
k, _, ok := l.GetOldest()
|
||||
if !ok {
|
||||
t.Fatalf("missing")
|
||||
}
|
||||
if k != 128 {
|
||||
t.Fatalf("bad: %v", k)
|
||||
}
|
||||
|
||||
k, _, ok = l.RemoveOldest()
|
||||
if !ok {
|
||||
t.Fatalf("missing")
|
||||
}
|
||||
if k != 128 {
|
||||
t.Fatalf("bad: %v", k)
|
||||
}
|
||||
|
||||
k, _, ok = l.RemoveOldest()
|
||||
if !ok {
|
||||
t.Fatalf("missing")
|
||||
}
|
||||
if k != 129 {
|
||||
t.Fatalf("bad: %v", k)
|
||||
}
|
||||
}
|
||||
|
||||
// Test that Add returns true/false if an eviction occurred
|
||||
func TestLRU_Add(t *testing.T) {
|
||||
evictCounter := 0
|
||||
onEvicted := func(k int, v int) {
|
||||
evictCounter++
|
||||
}
|
||||
|
||||
l, err := NewLRU(1, onEvicted)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
if l.Add(1, 1) == true || evictCounter != 0 {
|
||||
t.Errorf("should not have an eviction")
|
||||
}
|
||||
if l.Add(2, 2) == false || evictCounter != 1 {
|
||||
t.Errorf("should have an eviction")
|
||||
}
|
||||
}
|
||||
|
||||
// Test that Contains doesn't update recent-ness
|
||||
func TestLRU_Contains(t *testing.T) {
|
||||
l, err := NewLRU[int, int](2, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
l.Add(1, 1)
|
||||
l.Add(2, 2)
|
||||
if !l.Contains(1) {
|
||||
t.Errorf("1 should be contained")
|
||||
}
|
||||
|
||||
l.Add(3, 3)
|
||||
if l.Contains(1) {
|
||||
t.Errorf("Contains should not have updated recent-ness of 1")
|
||||
}
|
||||
}
|
||||
|
||||
// Test that Peek doesn't update recent-ness
|
||||
func TestLRU_Peek(t *testing.T) {
|
||||
l, err := NewLRU[int, int](2, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
l.Add(1, 1)
|
||||
l.Add(2, 2)
|
||||
if v, ok := l.Peek(1); !ok || v != 1 {
|
||||
t.Errorf("1 should be set to 1: %v, %v", v, ok)
|
||||
}
|
||||
|
||||
l.Add(3, 3)
|
||||
if l.Contains(1) {
|
||||
t.Errorf("should not have updated recent-ness of 1")
|
||||
}
|
||||
}
|
||||
|
||||
// Test that Resize can upsize and downsize
|
||||
func TestLRU_Resize(t *testing.T) {
|
||||
onEvictCounter := 0
|
||||
onEvicted := func(k int, v int) {
|
||||
onEvictCounter++
|
||||
}
|
||||
l, err := NewLRU(2, onEvicted)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
// Downsize
|
||||
l.Add(1, 1)
|
||||
l.Add(2, 2)
|
||||
evicted := l.Resize(1)
|
||||
if evicted != 1 {
|
||||
t.Errorf("1 element should have been evicted: %v", evicted)
|
||||
}
|
||||
if onEvictCounter != 1 {
|
||||
t.Errorf("onEvicted should have been called 1 time: %v", onEvictCounter)
|
||||
}
|
||||
|
||||
l.Add(3, 3)
|
||||
if l.Contains(1) {
|
||||
t.Errorf("Element 1 should have been evicted")
|
||||
}
|
||||
|
||||
// Upsize
|
||||
evicted = l.Resize(2)
|
||||
if evicted != 0 {
|
||||
t.Errorf("0 elements should have been evicted: %v", evicted)
|
||||
}
|
||||
|
||||
l.Add(4, 4)
|
||||
if !l.Contains(3) || !l.Contains(4) {
|
||||
t.Errorf("Cache should have contained 2 elements")
|
||||
}
|
||||
}
|
||||
|
||||
func (c *LRU[K, V]) wantKeys(t *testing.T, want []K) {
|
||||
t.Helper()
|
||||
got := c.Keys()
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Errorf("wrong keys got: %v, want: %v ", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCache_EvictionSameKey(t *testing.T) {
|
||||
var evictedKeys []int
|
||||
|
||||
cache, _ := NewLRU(
|
||||
2,
|
||||
func(key int, _ struct{}) {
|
||||
evictedKeys = append(evictedKeys, key)
|
||||
})
|
||||
|
||||
if evicted := cache.Add(1, struct{}{}); evicted {
|
||||
t.Error("First 1: got unexpected eviction")
|
||||
}
|
||||
cache.wantKeys(t, []int{1})
|
||||
|
||||
if evicted := cache.Add(2, struct{}{}); evicted {
|
||||
t.Error("2: got unexpected eviction")
|
||||
}
|
||||
cache.wantKeys(t, []int{1, 2})
|
||||
|
||||
if evicted := cache.Add(1, struct{}{}); evicted {
|
||||
t.Error("Second 1: got unexpected eviction")
|
||||
}
|
||||
cache.wantKeys(t, []int{2, 1})
|
||||
|
||||
if evicted := cache.Add(3, struct{}{}); !evicted {
|
||||
t.Error("3: did not get expected eviction")
|
||||
}
|
||||
cache.wantKeys(t, []int{1, 3})
|
||||
|
||||
want := []int{2}
|
||||
if !reflect.DeepEqual(evictedKeys, want) {
|
||||
t.Errorf("evictedKeys got: %v want: %v", evictedKeys, want)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package lru
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"math"
|
||||
"math/big"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func getRand(tb testing.TB) int64 {
|
||||
out, err := rand.Int(rand.Reader, big.NewInt(math.MaxInt64))
|
||||
if err != nil {
|
||||
tb.Fatal(err)
|
||||
}
|
||||
return out.Int64()
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
Copyright 2021 in-toto Developers
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
Copyright 2018 New York University
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2018-2024 Frank Denis
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 Josh Bleecher Snyder
|
||||
|
||||
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.
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
bin
|
||||
tags
|
||||
|
|
@ -1 +0,0 @@
|
|||
custom: https://letsencrypt.org/donate/
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
version: 2
|
||||
|
||||
updates:
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/"
|
||||
groups:
|
||||
aws:
|
||||
patterns:
|
||||
- "github.com/aws/*"
|
||||
otel:
|
||||
patterns:
|
||||
- "go.opentelemetry.io/*"
|
||||
open-pull-requests-limit: 1
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "wednesday"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: monthly
|
||||
open-pull-requests-limit: 1
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
---
|
||||
name: Default Template
|
||||
about: File a bug report or feature request
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
**Summary:**
|
||||
|
||||
|
||||
**Steps to reproduce:**
|
||||
|
||||
|
||||
**Expected result:**
|
||||
|
||||
|
||||
**Actual result:**
|
||||
|
||||
|
||||
**Additional details:**
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
# Boulder CI test suite workflow
|
||||
|
||||
name: Boulder CI
|
||||
|
||||
# Controls when the action will run.
|
||||
on:
|
||||
# Triggers the workflow on push or pull request events but only for the main branch
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release-branch-*
|
||||
pull_request:
|
||||
branches:
|
||||
- '**'
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
# Main test jobs. This looks like a single job, but the matrix
|
||||
# items will multiply it. For example every entry in the
|
||||
# BOULDER_TOOLS_TAG list will run with every test. If there were two
|
||||
# tags and 5 tests there would be 10 jobs run.
|
||||
b:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
strategy:
|
||||
# When set to true, GitHub cancels all in-progress jobs if any matrix job fails. Default: true
|
||||
fail-fast: false
|
||||
# Test matrix.
|
||||
matrix:
|
||||
# Add additional docker image tags here and all tests will be run with the additional image.
|
||||
BOULDER_TOOLS_TAG:
|
||||
- go1.24.4_2025-06-06
|
||||
# Tests command definitions. Use the entire "docker compose" command you want to run.
|
||||
tests:
|
||||
# Run ./test.sh --help for a description of each of the flags.
|
||||
- "./t.sh --lints --generate"
|
||||
- "./t.sh --integration"
|
||||
# Testing Config Changes:
|
||||
# Config changes that have landed in main but not yet been applied to
|
||||
# production can be made in `test/config-next/<component>.json`.
|
||||
#
|
||||
# Testing DB Schema Changes:
|
||||
# Database migrations in `sa/_db-next/migrations` are only performed
|
||||
# when `docker compose` is called using `-f docker-compose.yml -f
|
||||
# docker-compose.next.yml`.
|
||||
- "./tn.sh --integration"
|
||||
- "./t.sh --unit --enable-race-detection"
|
||||
- "./tn.sh --unit --enable-race-detection"
|
||||
- "./t.sh --start-py"
|
||||
|
||||
env:
|
||||
# This sets the docker image tag for the boulder-tools repository to
|
||||
# use in tests. It will be set appropriately for each tag in the list
|
||||
# defined in the matrix.
|
||||
BOULDER_TOOLS_TAG: ${{ matrix.BOULDER_TOOLS_TAG }}
|
||||
|
||||
# Sequence of tasks that will be executed as part of the job.
|
||||
steps:
|
||||
# Checks out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Docker Login
|
||||
# You may pin to the exact commit or the version.
|
||||
# uses: docker/login-action@f3364599c6aa293cdc2b8391b1b56d0c30e45c8a
|
||||
uses: docker/login-action@v3.4.0
|
||||
with:
|
||||
# Username used to log against the Docker registry
|
||||
username: ${{ secrets.DOCKER_USERNAME}}
|
||||
# Password or personal access token used to log against the Docker registry
|
||||
password: ${{ secrets.DOCKER_PASSWORD}}
|
||||
# Log out from the Docker registry at the end of a job
|
||||
logout: true
|
||||
continue-on-error: true
|
||||
|
||||
# Print the env variable being used to pull the docker image. For
|
||||
# informational use.
|
||||
- name: Print BOULDER_TOOLS_TAG
|
||||
run: echo "Using BOULDER_TOOLS_TAG ${BOULDER_TOOLS_TAG}"
|
||||
|
||||
# Pre-pull the docker containers before running the tests.
|
||||
- name: docker compose pull
|
||||
run: docker compose pull
|
||||
|
||||
# Run the test matrix. This will run
|
||||
- name: "Run Test: ${{ matrix.tests }}"
|
||||
run: ${{ matrix.tests }}
|
||||
|
||||
govulncheck:
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
# Checks out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
# When Go produces a security release, we want govulncheck to run
|
||||
# against the most recently released Go version.
|
||||
check-latest: true
|
||||
go-version: "stable"
|
||||
|
||||
- name: Run govulncheck
|
||||
run: go run golang.org/x/vuln/cmd/govulncheck@latest ./...
|
||||
|
||||
vendorcheck:
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
# When set to true, GitHub cancels all in-progress jobs if any matrix job fails. Default: true
|
||||
fail-fast: false
|
||||
matrix:
|
||||
go-version: [ '1.24.1' ]
|
||||
|
||||
steps:
|
||||
# Checks out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Go ${{ matrix.go-version }}
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
|
||||
- name: Verify vendor
|
||||
shell: bash
|
||||
run: |
|
||||
go mod tidy
|
||||
go mod vendor
|
||||
git diff --exit-code
|
||||
|
||||
|
||||
# This is a utility build job to detect if the status of any of the
|
||||
# above jobs have failed and fail if so. It is needed so there can be
|
||||
# one static job name that can be used to determine success of the job
|
||||
# in GitHub branch protection.
|
||||
# It does not block on the result of govulncheck so that a new vulnerability
|
||||
# disclosure does not prevent any other PRs from being merged.
|
||||
boulder_ci_test_matrix_status:
|
||||
permissions:
|
||||
contents: none
|
||||
if: ${{ always() }}
|
||||
runs-on: ubuntu-24.04
|
||||
name: Boulder CI Test Matrix
|
||||
needs:
|
||||
- b
|
||||
- vendorcheck
|
||||
steps:
|
||||
- name: Check boulder ci test matrix status
|
||||
if: ${{ needs.b.result != 'success' || needs.vendorcheck.result != 'success' }}
|
||||
run: exit 1
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
name: Check for IANA special-purpose address registry updates
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "20 16 * * *"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
check-iana-registries:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- name: Checkout iana/data from main branch
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: iana/data
|
||||
|
||||
# If the branch already exists, this will fail, which will remind us about
|
||||
# the outstanding PR.
|
||||
- name: Create an iana-registries-gha branch
|
||||
run: |
|
||||
git checkout --track origin/main -b iana-registries-gha
|
||||
|
||||
- name: Retrieve the IANA special-purpose address registries
|
||||
run: |
|
||||
IANA_IPV4="https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry-1.csv"
|
||||
IANA_IPV6="https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry-1.csv"
|
||||
|
||||
REPO_IPV4="iana/data/iana-ipv4-special-registry-1.csv"
|
||||
REPO_IPV6="iana/data/iana-ipv6-special-registry-1.csv"
|
||||
|
||||
curl --fail --location --show-error --silent --output "${REPO_IPV4}" "${IANA_IPV4}"
|
||||
curl --fail --location --show-error --silent --output "${REPO_IPV6}" "${IANA_IPV6}"
|
||||
|
||||
- name: Create a commit and pull request
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
shell:
|
||||
bash
|
||||
# `git diff --exit-code` returns an error code if there are any changes.
|
||||
run: |
|
||||
if ! git diff --exit-code; then
|
||||
git add iana/data/
|
||||
git config user.name "Irwin the IANA Bot"
|
||||
git commit \
|
||||
--message "Update IANA special-purpose address registries"
|
||||
git push origin HEAD
|
||||
gh pr create --fill
|
||||
fi
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
name: "Code Scanning - Action"
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ release-branch-*, main]
|
||||
push:
|
||||
branches: [ release-branch-*, main]
|
||||
|
||||
|
||||
jobs:
|
||||
CodeQL-Build:
|
||||
# CodeQL runs on ubuntu-latest, windows-latest, and macos-latest
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
# required for all workflows
|
||||
security-events: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
name: Check PR for changes that trigger CP/CPS review
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [ready_for_review, review_requested]
|
||||
paths:
|
||||
- 'features/features.go'
|
||||
|
||||
jobs:
|
||||
check-features:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: "stable"
|
||||
|
||||
- name: Checkout Upstream
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.base.ref }}
|
||||
- name: Get Current Flags
|
||||
run: go run ./test/list-features/list-features.go | sort >| /tmp/currflags.txt
|
||||
|
||||
- name: Checkout PR
|
||||
uses: actions/checkout@v4
|
||||
- name: Get PR Flags
|
||||
run: go run ./test/list-features/list-features.go | sort >| /tmp/prflags.txt
|
||||
|
||||
- name: Identify New Flags
|
||||
id: newflags
|
||||
run: echo flagnames=$(comm -13 /tmp/currflags.txt /tmp/prflags.txt | paste -sd,) >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Comment PR
|
||||
if: ${{ steps.newflags.outputs.flagnames != '' }}
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const { owner, repo, number: issue_number } = context.issue;
|
||||
|
||||
// No need to comment if the PR description already has a CPS review.
|
||||
const reviewRegexp = /^CPS Compliance Review:/;
|
||||
if (reviewRegexp.test(context.payload.pull_request.body)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No need to comment if this task has previously commented on this PR.
|
||||
const commentMarker = '<!-- cps_review_check -->';
|
||||
const comments = await github.rest.issues.listComments({
|
||||
owner,
|
||||
repo,
|
||||
issue_number
|
||||
});
|
||||
if (comments.data.find(c => c.body.includes(commentMarker))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No existing review or comment found, post the comment.
|
||||
const prAuthor = context.payload.pull_request.user.login;
|
||||
const flagNames = '${{ steps.newflags.outputs.flagnames }}';
|
||||
const commentBody = `${commentMarker}\n@${prAuthor}, this PR adds one or more new feature flags: ${flagNames}. As such, this PR must be accompanied by a review of the Let's Encrypt CP/CPS to ensure that our behavior both before and after this flag is flipped is compliant with that document.\n\nPlease conduct such a review, then add your findings to the PR description in a paragraph beginning with "CPS Compliance Review:".`;
|
||||
await github.rest.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
issue_number,
|
||||
body: commentBody
|
||||
});
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
name: Check PR for configuration and SQL changes
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [review_requested]
|
||||
paths:
|
||||
- 'test/config-next/*.json'
|
||||
- 'test/config-next/*.yaml'
|
||||
- 'test/config-next/*.yml'
|
||||
- 'sa/db-users/*.sql'
|
||||
- 'sa/db-next/**/*.sql'
|
||||
- 'sa/db/**/*.sql'
|
||||
|
||||
jobs:
|
||||
check-changes:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Comment PR
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const commentMarker = '<!-- deployment_ticket_check -->';
|
||||
const prAuthor = context.payload.pull_request.user.login;
|
||||
const commentBody = `${commentMarker}\n@${prAuthor}, this PR appears to contain configuration and/or SQL schema changes. Please ensure that a corresponding deployment ticket has been filed with the new values.\n`;
|
||||
const { owner, repo, number: issue_number } = context.issue;
|
||||
const issueRegexp = /IN-\d+/;
|
||||
|
||||
// Get PR body and all issue comments.
|
||||
const prBody = context.payload.pull_request.body;
|
||||
const comments = await github.rest.issues.listComments({
|
||||
owner,
|
||||
repo,
|
||||
issue_number
|
||||
});
|
||||
|
||||
if (issueRegexp.test(prBody) || comments.data.some(c => issueRegexp.test(c.body))) {
|
||||
// Issue number exists in PR body or comments.
|
||||
return;
|
||||
}
|
||||
|
||||
if (comments.data.find(c => c.body.includes(commentMarker))) {
|
||||
// Comment already exists.
|
||||
return;
|
||||
}
|
||||
|
||||
// No issue number or comment were found, post the comment.
|
||||
await github.rest.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
issue_number,
|
||||
body: commentBody
|
||||
});
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
# This GitHub Action runs only on pushes to main or a hotfix branch. It can
|
||||
# be used by tag protection rules to ensure that tags may only be pushed if
|
||||
# their corresponding commit was first pushed to one of those branches.
|
||||
name: Merged to main (or hotfix)
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- release-branch-*
|
||||
jobs:
|
||||
merged-to-main:
|
||||
name: Merged to main (or hotfix)
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
# Build the Boulder Debian package on every PR, push to main, and tag push. On
|
||||
# tag pushes, additionally create a GitHub release and with the resulting Debian
|
||||
# package.
|
||||
# Keep in sync with try-release.yml, with the exception that try-release.yml
|
||||
# can have multiple entries in its matrix but this should only have one.
|
||||
name: Build release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- release-*
|
||||
|
||||
jobs:
|
||||
push-release:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
GO_VERSION:
|
||||
- "1.24.4"
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
fetch-depth: '0' # Needed for verify-release-ancestry.sh to see origin/main
|
||||
|
||||
- name: Verify release ancestry
|
||||
run: ./tools/verify-release-ancestry.sh "$GITHUB_SHA"
|
||||
|
||||
- name: Build .deb
|
||||
id: build
|
||||
env:
|
||||
GO_VERSION: ${{ matrix.GO_VERSION }}
|
||||
run: docker run -v $PWD:/boulder -e GO_VERSION=$GO_VERSION -e COMMIT_ID="$(git rev-parse --short=8 HEAD)" ubuntu:24.04 bash -c 'apt update && apt -y install gnupg2 curl sudo git gcc && cd /boulder/ && ./tools/make-assets.sh'
|
||||
|
||||
- name: Compute checksums
|
||||
id: checksums
|
||||
# The files listed on this line must be identical to the files uploaded
|
||||
# in the last step.
|
||||
run: sha256sum boulder*.deb boulder*.tar.gz >| boulder-${{ matrix.GO_VERSION }}.$(date +%s)-$(git rev-parse --short=8 HEAD).checksums.txt
|
||||
|
||||
- name: Create release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# https://cli.github.com/manual/gh_release_create
|
||||
run: gh release create "${GITHUB_REF_NAME}"
|
||||
continue-on-error: true
|
||||
|
||||
- name: Upload release files
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# https://cli.github.com/manual/gh_release_upload
|
||||
run: gh release upload "${GITHUB_REF_NAME}" boulder*.deb boulder*.tar.gz boulder*.checksums.txt
|
||||
|
||||
- name: Build ct-test-srv Container
|
||||
run: docker buildx build . --build-arg "GO_VERSION=${{ matrix.GO_VERSION }}" -f test/ct-test-srv/Dockerfile -t "ghcr.io/letsencrypt/ct-test-srv:${{ github.ref_name }}-go${{ matrix.GO_VERSION }}"
|
||||
|
||||
- name: Login to ghcr.io
|
||||
run: printenv GITHUB_TOKEN | docker login ghcr.io -u "${{ github.actor }}" --password-stdin
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Push ct-test-srv Container
|
||||
run: docker push "ghcr.io/letsencrypt/ct-test-srv:${{ github.ref_name }}-go${{ matrix.GO_VERSION }}"
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
# Try building the Boulder Debian package on every PR and push to main.
|
||||
# This is to make sure the actual release job will succeed when we tag a
|
||||
# release.
|
||||
# Keep in sync with release.yml
|
||||
name: Try release
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
try-release:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
GO_VERSION:
|
||||
- "1.24.4"
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Build .deb
|
||||
id: build
|
||||
env:
|
||||
GO_VERSION: ${{ matrix.GO_VERSION }}
|
||||
run: docker run -v $PWD:/boulder -e GO_VERSION=$GO_VERSION -e COMMIT_ID="$(git rev-parse --short=8 HEAD)" ubuntu:24.04 bash -c 'apt update && apt -y install gnupg2 curl sudo git gcc && cd /boulder/ && ./tools/make-assets.sh'
|
||||
|
||||
- name: Compute checksums
|
||||
id: checksums
|
||||
# The files listed on this line must be identical to the files uploaded
|
||||
# in the last step of the real release action.
|
||||
run: sha256sum boulder*.deb boulder*.tar.gz >| boulder-${{ matrix.GO_VERSION }}.$(date +%s)-$(git rev-parse --short=8 HEAD).checksums.txt
|
||||
|
||||
- name: List files
|
||||
id: files
|
||||
run: ls boulder*.deb boulder*.tar.gz boulder*.checksums.txt
|
||||
|
||||
- name: Show checksums
|
||||
id: check
|
||||
run: cat boulder*.checksums.txt
|
||||
|
||||
- name: Build ct-test-srv Container
|
||||
run: docker buildx build . --build-arg "GO_VERSION=${{ matrix.GO_VERSION }}" -f test/ct-test-srv/Dockerfile -t "ghcr.io/letsencrypt/ct-test-srv:${{ github.sha }}-go${{ matrix.GO_VERSION }}"
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
*.pyc
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
bin
|
||||
.gocache
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
# Vim swap files
|
||||
*.sw?
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.sw?
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
*.coverprofile
|
||||
|
||||
tags
|
||||
|
||||
# IDE support files
|
||||
.idea
|
||||
|
||||
.vscode/*
|
||||
|
||||
# ProxySQL log files
|
||||
test/proxysql/*.log*
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
version: "2"
|
||||
linters:
|
||||
default: none
|
||||
enable:
|
||||
- asciicheck
|
||||
- bidichk
|
||||
- errcheck
|
||||
- gosec
|
||||
- govet
|
||||
- ineffassign
|
||||
- misspell
|
||||
- nolintlint
|
||||
- spancheck
|
||||
- sqlclosecheck
|
||||
- staticcheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
- wastedassign
|
||||
settings:
|
||||
errcheck:
|
||||
exclude-functions:
|
||||
- (net/http.ResponseWriter).Write
|
||||
- (net.Conn).Write
|
||||
- encoding/binary.Write
|
||||
- io.Write
|
||||
- net/http.Write
|
||||
- os.Remove
|
||||
- github.com/miekg/dns.WriteMsg
|
||||
govet:
|
||||
disable:
|
||||
- fieldalignment
|
||||
- shadow
|
||||
enable-all: true
|
||||
settings:
|
||||
printf:
|
||||
funcs:
|
||||
- (github.com/letsencrypt/boulder/log.Logger).Errf
|
||||
- (github.com/letsencrypt/boulder/log.Logger).Warningf
|
||||
- (github.com/letsencrypt/boulder/log.Logger).Infof
|
||||
- (github.com/letsencrypt/boulder/log.Logger).Debugf
|
||||
- (github.com/letsencrypt/boulder/log.Logger).AuditInfof
|
||||
- (github.com/letsencrypt/boulder/log.Logger).AuditErrf
|
||||
- (github.com/letsencrypt/boulder/ocsp/responder).SampledError
|
||||
- (github.com/letsencrypt/boulder/web.RequestEvent).AddError
|
||||
gosec:
|
||||
excludes:
|
||||
# TODO: Identify, fix, and remove violations of most of these rules
|
||||
- G101 # Potential hardcoded credentials
|
||||
- G102 # Binds to all network interfaces
|
||||
- G104 # Errors unhandled
|
||||
- G107 # Potential HTTP request made with variable url
|
||||
- G201 # SQL string formatting
|
||||
- G202 # SQL string concatenation
|
||||
- G204 # Subprocess launched with variable
|
||||
- G302 # Expect file permissions to be 0600 or less
|
||||
- G306 # Expect WriteFile permissions to be 0600 or less
|
||||
- G304 # Potential file inclusion via variable
|
||||
- G401 # Use of weak cryptographic primitive
|
||||
- G402 # TLS InsecureSkipVerify set true.
|
||||
- G403 # RSA keys should be at least 2048 bits
|
||||
- G404 # Use of weak random number generator
|
||||
nolintlint:
|
||||
require-explanation: true
|
||||
require-specific: true
|
||||
allow-unused: false
|
||||
staticcheck:
|
||||
checks:
|
||||
- all
|
||||
# TODO: Identify, fix, and remove violations of most of these rules
|
||||
- -S1029 # Range over the string directly
|
||||
- -SA1019 # Using a deprecated function, variable, constant or field
|
||||
- -SA6003 # Converting a string to a slice of runes before ranging over it
|
||||
- -ST1000 # Incorrect or missing package comment
|
||||
- -ST1003 # Poorly chosen identifier
|
||||
- -ST1005 # Incorrectly formatted error string
|
||||
- -QF1001 # Could apply De Morgan's law
|
||||
- -QF1003 # Could use tagged switch
|
||||
- -QF1004 # Could use strings.Split instead
|
||||
- -QF1007 # Could merge conditional assignment into variable declaration
|
||||
- -QF1008 # Could remove embedded field from selector
|
||||
- -QF1009 # Probably want to use time.Time.Equal
|
||||
- -QF1012 # Use fmt.Fprintf(...) instead of Write(fmt.Sprintf(...))
|
||||
exclusions:
|
||||
presets:
|
||||
- std-error-handling
|
||||
formatters:
|
||||
enable:
|
||||
- gofmt
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
[files]
|
||||
extend-exclude = [
|
||||
".git/",
|
||||
"go.mod",
|
||||
"go.sum",
|
||||
"vendor/",
|
||||
]
|
||||
ignore-hidden = false
|
||||
|
||||
[default]
|
||||
extend-ignore-re = [
|
||||
# Anything base64 or base64url longer than 36 chars is probably encoded.
|
||||
'\b[0-9A-Za-z+/]{36,}\b',
|
||||
'\b[0-9A-Za-z_-]{36,}\b',
|
||||
"0002a4ba3cf408927759",
|
||||
"65CuDAA",
|
||||
'"sql_warnings", "TrUe"',
|
||||
'"tx_read_only", "FalSe"',
|
||||
"evenMOREcaps",
|
||||
'"iSsUe"',
|
||||
]
|
||||
|
||||
[default.extend-words]
|
||||
# Extended DNS Error
|
||||
"ede" = "ede"
|
||||
# Alternative spelling
|
||||
"unmarshaling" = "unmarshaling"
|
||||
|
||||
[default.extend-identifiers]
|
||||
"caaFailer" = "caaFailer"
|
||||
"challStrat" = "challStrat"
|
||||
"ExpectedStratType" = "ExpectedStratType"
|
||||
"otConf" = "otConf"
|
||||
"serInt" = "serInt"
|
||||
"StratName" = "StratName"
|
||||
"typ" = "typ"
|
||||
"UPDATEs" = "UPDATEs"
|
||||
"vai" = "vai"
|
||||
|
|
@ -1 +0,0 @@
|
|||
* @letsencrypt/boulder-developers
|
||||
|
|
@ -1,375 +0,0 @@
|
|||
Copyright 2016 ISRG. All rights reserved.
|
||||
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
OBJDIR ?= $(shell pwd)/bin
|
||||
DESTDIR ?= /usr/local/bin
|
||||
ARCHIVEDIR ?= /tmp
|
||||
|
||||
VERSION ?= 1.0.0
|
||||
EPOCH ?= 1
|
||||
MAINTAINER ?= "Community"
|
||||
|
||||
CMDS = admin boulder ceremony ct-test-srv pardot-test-srv chall-test-srv
|
||||
CMD_BINS = $(addprefix bin/, $(CMDS) )
|
||||
OBJECTS = $(CMD_BINS)
|
||||
|
||||
# Build environment variables (referencing core/util.go)
|
||||
COMMIT_ID = $(shell git rev-parse --short=8 HEAD)
|
||||
|
||||
BUILD_ID = $(shell git symbolic-ref --short=8 HEAD 2>/dev/null) +$(COMMIT_ID)
|
||||
BUILD_ID_VAR = github.com/letsencrypt/boulder/core.BuildID
|
||||
|
||||
BUILD_HOST = $(shell whoami)@$(shell hostname)
|
||||
BUILD_HOST_VAR = github.com/letsencrypt/boulder/core.BuildHost
|
||||
|
||||
BUILD_TIME = $(shell date -u)
|
||||
BUILD_TIME_VAR = github.com/letsencrypt/boulder/core.BuildTime
|
||||
|
||||
GO_BUILD_FLAGS = -ldflags "-X \"$(BUILD_ID_VAR)=$(BUILD_ID)\" -X \"$(BUILD_TIME_VAR)=$(BUILD_TIME)\" -X \"$(BUILD_HOST_VAR)=$(BUILD_HOST)\""
|
||||
|
||||
.PHONY: all build build_cmds deb tar
|
||||
all: build
|
||||
|
||||
build: $(OBJECTS)
|
||||
|
||||
$(OBJDIR):
|
||||
@mkdir -p $(OBJDIR)
|
||||
|
||||
$(CMD_BINS): build_cmds
|
||||
|
||||
build_cmds: | $(OBJDIR)
|
||||
echo $(OBJECTS)
|
||||
GOBIN=$(OBJDIR) GO111MODULE=on go install -mod=vendor $(GO_BUILD_FLAGS) ./...
|
||||
|
||||
# Building a .deb requires `fpm` from https://github.com/jordansissel/fpm
|
||||
# which you can install with `gem install fpm`.
|
||||
# It is recommended that maintainers use environment overrides to specify
|
||||
# Version and Epoch, such as:
|
||||
#
|
||||
# VERSION=0.1.9 EPOCH=52 MAINTAINER="$(whoami)" ARCHIVEDIR=/tmp make build deb
|
||||
deb: build
|
||||
fpm -f -s dir -t deb --name "boulder" \
|
||||
--license "Mozilla Public License v2.0" --vendor "ISRG" \
|
||||
--url "https://github.com/letsencrypt/boulder" --prefix=/opt/boulder \
|
||||
--version "$(VERSION)" --iteration "$(COMMIT_ID)" --epoch "$(EPOCH)" \
|
||||
--package "$(ARCHIVEDIR)/boulder-$(VERSION)-$(COMMIT_ID).x86_64.deb" \
|
||||
--description "Boulder is an ACME-compatible X.509 Certificate Authority" \
|
||||
--maintainer "$(MAINTAINER)" \
|
||||
test/config/ sa/db data/ $(OBJECTS)
|
||||
|
||||
tar: build
|
||||
fpm -f -s dir -t tar --name "boulder" --prefix=/opt/boulder \
|
||||
--package "$(ARCHIVEDIR)/boulder-$(VERSION)-$(COMMIT_ID).amd64.tar" \
|
||||
test/config/ sa/db data/ $(OBJECTS)
|
||||
gzip -f "$(ARCHIVEDIR)/boulder-$(VERSION)-$(COMMIT_ID).amd64.tar"
|
||||
286
third-party/github.com/letsencrypt/boulder/README.md
vendored
286
third-party/github.com/letsencrypt/boulder/README.md
vendored
|
|
@ -1,286 +0,0 @@
|
|||
# Boulder - An ACME CA
|
||||
|
||||
[](https://github.com/letsencrypt/boulder/actions/workflows/boulder-ci.yml?query=branch%3Amain)
|
||||
|
||||
This is an implementation of an ACME-based CA. The [ACME
|
||||
protocol](https://github.com/ietf-wg-acme/acme/) allows the CA to automatically
|
||||
verify that an applicant for a certificate actually controls an identifier, and
|
||||
allows subscribers to issue and revoke certificates for the identifiers they
|
||||
control. Boulder is the software that runs [Let's
|
||||
Encrypt](https://letsencrypt.org).
|
||||
|
||||
## Contents
|
||||
|
||||
* [Overview](#overview)
|
||||
* [Setting up Boulder](#setting-up-boulder)
|
||||
* [Development](#development)
|
||||
* [Working with Certbot](#working-with-certbot)
|
||||
* [Working with another ACME Client](#working-with-another-acme-client)
|
||||
* [Production](#production)
|
||||
* [Contributing](#contributing)
|
||||
* [License](#license)
|
||||
|
||||
## Overview
|
||||
|
||||
Boulder is divided into the following main components:
|
||||
|
||||
1. Web Front Ends (one per API version)
|
||||
2. Registration Authority
|
||||
3. Validation Authority
|
||||
4. Certificate Authority
|
||||
5. Storage Authority
|
||||
6. Publisher
|
||||
7. OCSP Responder
|
||||
8. CRL Updater
|
||||
|
||||
This component model lets us separate the function of the CA by security
|
||||
context. The Web Front End, Validation Authority, OCSP Responder and
|
||||
Publisher need access to the Internet, which puts them at greater risk of
|
||||
compromise. The Registration Authority can live without Internet
|
||||
connectivity, but still needs to talk to the Web Front End and Validation
|
||||
Authority. The Certificate Authority need only receive instructions from the
|
||||
Registration Authority. All components talk to the SA for storage, so most
|
||||
lines indicating SA RPCs are not shown here.
|
||||
|
||||
```text
|
||||
CA ---------> Publisher
|
||||
^
|
||||
|
|
||||
Subscriber -> WFE --> RA --> SA --> MariaDB
|
||||
| ^
|
||||
Subscriber server <- VA <----+ |
|
||||
|
|
||||
Browser -------------------> OCSP Responder
|
||||
```
|
||||
|
||||
Internally, the logic of the system is based around five types of objects:
|
||||
accounts, authorizations, challenges, orders and certificates, mapping directly
|
||||
to the resources of the same name in ACME. Requests from ACME clients result in
|
||||
new objects and changes to objects. The Storage Authority maintains persistent
|
||||
copies of the current set of objects.
|
||||
|
||||
Boulder uses gRPC for inter-component communication. For components that you
|
||||
want to be remote, it is necessary to instantiate a "client" and "server" for
|
||||
that component. The client implements the component's Go interface, while the
|
||||
server has the actual logic for the component. A high level overview for this
|
||||
communication model can be found in the [gRPC
|
||||
documentation](https://www.grpc.io/docs/).
|
||||
|
||||
The full details of how the various ACME operations happen in Boulder are
|
||||
laid out in
|
||||
[DESIGN.md](https://github.com/letsencrypt/boulder/blob/main/docs/DESIGN.md).
|
||||
|
||||
## Setting up Boulder
|
||||
|
||||
### Development
|
||||
|
||||
Boulder has a Dockerfile and uses Docker Compose to make it easy to install
|
||||
and set up all its dependencies. This is how the maintainers work on Boulder,
|
||||
and is our main recommended way to run it for development/experimentation. It
|
||||
is not suitable for use as a production environment.
|
||||
|
||||
While we aim to make Boulder easy to setup ACME client developers may find
|
||||
[Pebble](https://github.com/letsencrypt/pebble), a miniature version of
|
||||
Boulder, to be better suited for continuous integration and quick
|
||||
experimentation.
|
||||
|
||||
We recommend setting git's [fsckObjects
|
||||
setting](https://groups.google.com/forum/#!topic/binary-transparency/f-BI4o8HZW0/discussion)
|
||||
before getting a copy of Boulder to have better integrity guarantees for
|
||||
updates.
|
||||
|
||||
Clone the boulder repository:
|
||||
|
||||
```shell
|
||||
git clone https://github.com/letsencrypt/boulder/
|
||||
cd boulder
|
||||
```
|
||||
|
||||
Additionally, make sure you have Docker Engine 1.13.0+ and Docker Compose
|
||||
1.10.0+ installed. If you do not, you can follow Docker's [installation
|
||||
instructions](https://docs.docker.com/compose/install/).
|
||||
|
||||
We recommend having **at least 2GB of RAM** available on your Docker host. In
|
||||
practice using less RAM may result in the MariaDB container failing in
|
||||
non-obvious ways.
|
||||
|
||||
To start Boulder in a Docker container, run:
|
||||
|
||||
```shell
|
||||
docker compose up
|
||||
```
|
||||
|
||||
To run our standard battery of tests (lints, unit, integration):
|
||||
|
||||
```shell
|
||||
docker compose run --use-aliases boulder ./test.sh
|
||||
```
|
||||
|
||||
To run all unit tests:
|
||||
|
||||
```shell
|
||||
docker compose run --use-aliases boulder ./test.sh --unit
|
||||
```
|
||||
|
||||
To run specific unit tests (example is of the ./va directory):
|
||||
|
||||
```shell
|
||||
docker compose run --use-aliases boulder ./test.sh --unit --filter=./va
|
||||
```
|
||||
|
||||
To run all integration tests:
|
||||
|
||||
```shell
|
||||
docker compose run --use-aliases boulder ./test.sh --integration
|
||||
```
|
||||
|
||||
To run specific integration tests (example runs TestAkamaiPurgerDrainQueueFails and TestWFECORS):
|
||||
|
||||
```shell
|
||||
docker compose run --use-aliases boulder ./test.sh --filter TestAkamaiPurgerDrainQueueFails/TestWFECORS
|
||||
```
|
||||
|
||||
To get a list of available integration tests:
|
||||
|
||||
```shell
|
||||
docker compose run --use-aliases boulder ./test.sh --list-integration-tests
|
||||
```
|
||||
|
||||
The configuration in docker-compose.yml mounts your boulder checkout at
|
||||
/boulder so you can edit code on your host and it will be immediately
|
||||
reflected inside the Docker containers run with `docker compose`.
|
||||
|
||||
If you have problems with Docker, you may want to try [removing all
|
||||
containers and
|
||||
volumes](https://www.digitalocean.com/community/tutorials/how-to-remove-docker-images-containers-and-volumes).
|
||||
|
||||
By default, Boulder uses a fake DNS resolver that resolves all hostnames to
|
||||
127.0.0.1. This is suitable for running integration tests inside the Docker
|
||||
container. If you want Boulder to be able to communicate with a client
|
||||
running on your host instead, you should find your host's Docker IP with:
|
||||
|
||||
```shell
|
||||
ifconfig docker0 | grep "inet addr:" | cut -d: -f2 | awk '{ print $1}'
|
||||
```
|
||||
|
||||
And edit docker-compose.yml to change the `FAKE_DNS` environment variable to
|
||||
match. This will cause Boulder's stubbed-out DNS resolver (`sd-test-srv`) to
|
||||
respond to all A queries with the address in `FAKE_DNS`.
|
||||
|
||||
If you use a host-based firewall (e.g. `ufw` or `iptables`) make sure you allow
|
||||
connections from the Docker instance to your host on the required validation
|
||||
ports to your ACME client.
|
||||
|
||||
Alternatively, you can override the docker-compose.yml default with an
|
||||
environmental variable using -e (replace 172.17.0.1 with the host IPv4
|
||||
address found in the command above)
|
||||
|
||||
```shell
|
||||
docker compose run --use-aliases -e FAKE_DNS=172.17.0.1 --service-ports boulder ./start.py
|
||||
```
|
||||
|
||||
Running tests without the `./test.sh` wrapper:
|
||||
|
||||
Run all unit tests
|
||||
|
||||
```shell
|
||||
docker compose run --use-aliases boulder go test -p 1 ./...
|
||||
```
|
||||
|
||||
Run unit tests for a specific directory:
|
||||
|
||||
```shell
|
||||
docker compose run --use-aliases boulder go test <DIRECTORY>
|
||||
```
|
||||
|
||||
Run integration tests (omit `--filter <REGEX>` to run all):
|
||||
|
||||
```shell
|
||||
docker compose run --use-aliases boulder python3 test/integration-test.py --chisel --gotest --filter <REGEX>
|
||||
```
|
||||
|
||||
### Working with Certbot
|
||||
|
||||
Check out the Certbot client from https://github.com/certbot/certbot and
|
||||
follow their setup instructions. Once you've got the client set up, you'll
|
||||
probably want to run it against your local Boulder. There are a number of
|
||||
command line flags that are necessary to run the client against a local
|
||||
Boulder, and without root access. The simplest way to run the client locally
|
||||
is to use a convenient alias for certbot (`certbot_test`) with a custom
|
||||
`SERVER` environment variable:
|
||||
|
||||
```shell
|
||||
SERVER=http://localhost:4001/directory certbot_test certonly --standalone -d test.example.com
|
||||
```
|
||||
|
||||
Your local Boulder instance uses a fake DNS resolver that returns 127.0.0.1
|
||||
for any query, so you can use any value for the -d flag. To return an answer
|
||||
other than `127.0.0.1` change the Boulder `FAKE_DNS` environment variable to
|
||||
another IP address.
|
||||
|
||||
### Working with another ACME Client
|
||||
|
||||
Once you have followed the Boulder development environment instructions and have
|
||||
started the containers you will find the ACME endpoints exposed to your host at
|
||||
the following URLs:
|
||||
|
||||
* ACME v2, HTTP: `http://localhost:4001/directory`
|
||||
* ACME v2, HTTPS: `https://localhost:4431/directory`
|
||||
|
||||
To access the HTTPS versions of the endpoints you will need to configure your
|
||||
ACME client software to use a CA truststore that contains the
|
||||
`test/certs/ipki/minica.pem` CA certificate. See
|
||||
[`test/certs/README.md`](https://github.com/letsencrypt/boulder/blob/main/test/certs/README.md)
|
||||
for more information.
|
||||
|
||||
Your local Boulder instance uses a fake DNS resolver that returns 127.0.0.1
|
||||
for any query, allowing you to issue certificates for any domain as if it
|
||||
resolved to your localhost. To return an answer other than `127.0.0.1` change
|
||||
the Boulder `FAKE_DNS` environment variable to another IP address.
|
||||
|
||||
Most often you will want to configure `FAKE_DNS` to point to your host
|
||||
machine where you run an ACME client.
|
||||
|
||||
### Production
|
||||
|
||||
Boulder is custom built for Let's Encrypt and is intended only to support the
|
||||
Web PKI and the CA/Browser forum's baseline requirements. In our experience
|
||||
often Boulder is not the right fit for organizations that are evaluating it for
|
||||
production usage. In most cases a centrally managed PKI that doesn't require
|
||||
domain-authorization with ACME is a better choice. For this environment we
|
||||
recommend evaluating a project other than Boulder.
|
||||
|
||||
We offer a brief [deployment and implementation
|
||||
guide](https://github.com/letsencrypt/boulder/wiki/Deployment-&-Implementation-Guide)
|
||||
that describes some of the required work and security considerations involved in
|
||||
using Boulder in a production environment. As-is the docker based Boulder
|
||||
development environment is **not suitable for
|
||||
production usage**. It uses private key material that is publicly available,
|
||||
exposes debug ports and is brittle to component failure.
|
||||
|
||||
While we are supportive of other organization's deploying Boulder in
|
||||
a production setting we prioritize support and development work that favors
|
||||
Let's Encrypt's mission. This means we may not be able to provide timely support
|
||||
or accept pull-requests that deviate significantly from our first line goals. If
|
||||
you've thoroughly evaluated the alternatives and Boulder is definitely the best
|
||||
fit we're happy to answer questions to the best of our ability.
|
||||
|
||||
## Contributing
|
||||
|
||||
Please take a look at
|
||||
[CONTRIBUTING.md](https://github.com/letsencrypt/boulder/blob/main/docs/CONTRIBUTING.md)
|
||||
for our guidelines on submitting patches, code review process, code of conduct,
|
||||
and various other tips related to working on the codebase.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
The code of conduct for everyone participating in this community in any capacity
|
||||
is available for reference
|
||||
[on the community forum](https://community.letsencrypt.org/guidelines).
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the Mozilla Public License 2.0, the full text
|
||||
of which can be found in the
|
||||
[LICENSE.txt](https://github.com/letsencrypt/boulder/blob/main/LICENSE.txt)
|
||||
file.
|
||||
|
|
@ -1,402 +0,0 @@
|
|||
package akamai
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/md5" //nolint: gosec // MD5 is required by the Akamai API.
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/jmhodges/clock"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"golang.org/x/crypto/ocsp"
|
||||
|
||||
"github.com/letsencrypt/boulder/core"
|
||||
blog "github.com/letsencrypt/boulder/log"
|
||||
"github.com/letsencrypt/boulder/metrics"
|
||||
)
|
||||
|
||||
const (
|
||||
timestampFormat = "20060102T15:04:05-0700"
|
||||
v3PurgePath = "/ccu/v3/delete/url/"
|
||||
v3PurgeTagPath = "/ccu/v3/delete/tag/"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrAllRetriesFailed indicates that all purge submission attempts have
|
||||
// failed.
|
||||
ErrAllRetriesFailed = errors.New("all attempts to submit purge request failed")
|
||||
|
||||
// errFatal is returned by the purge method of CachePurgeClient to indicate
|
||||
// that it failed for a reason that cannot be remediated by retrying the
|
||||
// request.
|
||||
errFatal = errors.New("fatal error")
|
||||
)
|
||||
|
||||
type v3PurgeRequest struct {
|
||||
Objects []string `json:"objects"`
|
||||
}
|
||||
|
||||
type purgeResponse struct {
|
||||
HTTPStatus int `json:"httpStatus"`
|
||||
Detail string `json:"detail"`
|
||||
EstimatedSeconds int `json:"estimatedSeconds"`
|
||||
PurgeID string `json:"purgeId"`
|
||||
}
|
||||
|
||||
// CachePurgeClient talks to the Akamai CCU REST API. It is safe to make
|
||||
// concurrent requests using this client.
|
||||
type CachePurgeClient struct {
|
||||
client *http.Client
|
||||
apiEndpoint string
|
||||
apiHost string
|
||||
apiScheme string
|
||||
clientToken string
|
||||
clientSecret string
|
||||
accessToken string
|
||||
v3Network string
|
||||
retries int
|
||||
retryBackoff time.Duration
|
||||
log blog.Logger
|
||||
purgeLatency prometheus.Histogram
|
||||
purges *prometheus.CounterVec
|
||||
clk clock.Clock
|
||||
}
|
||||
|
||||
// NewCachePurgeClient performs some basic validation of supplied configuration
|
||||
// and returns a newly constructed CachePurgeClient.
|
||||
func NewCachePurgeClient(
|
||||
baseURL,
|
||||
clientToken,
|
||||
secret,
|
||||
accessToken,
|
||||
network string,
|
||||
retries int,
|
||||
retryBackoff time.Duration,
|
||||
log blog.Logger, scope prometheus.Registerer,
|
||||
) (*CachePurgeClient, error) {
|
||||
if network != "production" && network != "staging" {
|
||||
return nil, fmt.Errorf("'V3Network' must be \"staging\" or \"production\", got %q", network)
|
||||
}
|
||||
|
||||
endpoint, err := url.Parse(strings.TrimSuffix(baseURL, "/"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse 'BaseURL' as a URL: %s", err)
|
||||
}
|
||||
|
||||
purgeLatency := prometheus.NewHistogram(prometheus.HistogramOpts{
|
||||
Name: "ccu_purge_latency",
|
||||
Help: "Histogram of latencies of CCU purges",
|
||||
Buckets: metrics.InternetFacingBuckets,
|
||||
})
|
||||
scope.MustRegister(purgeLatency)
|
||||
|
||||
purges := prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: "ccu_purges",
|
||||
Help: "A counter of CCU purges labelled by the result",
|
||||
}, []string{"type"})
|
||||
scope.MustRegister(purges)
|
||||
|
||||
return &CachePurgeClient{
|
||||
client: new(http.Client),
|
||||
apiEndpoint: endpoint.String(),
|
||||
apiHost: endpoint.Host,
|
||||
apiScheme: strings.ToLower(endpoint.Scheme),
|
||||
clientToken: clientToken,
|
||||
clientSecret: secret,
|
||||
accessToken: accessToken,
|
||||
v3Network: network,
|
||||
retries: retries,
|
||||
retryBackoff: retryBackoff,
|
||||
log: log,
|
||||
clk: clock.New(),
|
||||
purgeLatency: purgeLatency,
|
||||
purges: purges,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// makeAuthHeader constructs a special Akamai authorization header. This header
|
||||
// is used to identify clients to Akamai's EdgeGrid APIs. For a more detailed
|
||||
// description of the generation process see their docs:
|
||||
// https://developer.akamai.com/introduction/Client_Auth.html
|
||||
func (cpc *CachePurgeClient) makeAuthHeader(body []byte, apiPath string, nonce string) string {
|
||||
// The akamai API is very time sensitive (recommending reliance on a stratum 2
|
||||
// or better time source). Additionally, timestamps MUST be in UTC.
|
||||
timestamp := cpc.clk.Now().UTC().Format(timestampFormat)
|
||||
header := fmt.Sprintf(
|
||||
"EG1-HMAC-SHA256 client_token=%s;access_token=%s;timestamp=%s;nonce=%s;",
|
||||
cpc.clientToken,
|
||||
cpc.accessToken,
|
||||
timestamp,
|
||||
nonce,
|
||||
)
|
||||
bodyHash := sha256.Sum256(body)
|
||||
tbs := fmt.Sprintf(
|
||||
"%s\t%s\t%s\t%s\t%s\t%s\t%s",
|
||||
"POST",
|
||||
cpc.apiScheme,
|
||||
cpc.apiHost,
|
||||
apiPath,
|
||||
// Signed headers are not required for this request type.
|
||||
"",
|
||||
base64.StdEncoding.EncodeToString(bodyHash[:]),
|
||||
header,
|
||||
)
|
||||
cpc.log.Debugf("To-be-signed Akamai EdgeGrid authentication %q", tbs)
|
||||
|
||||
h := hmac.New(sha256.New, signingKey(cpc.clientSecret, timestamp))
|
||||
h.Write([]byte(tbs))
|
||||
return fmt.Sprintf(
|
||||
"%ssignature=%s",
|
||||
header,
|
||||
base64.StdEncoding.EncodeToString(h.Sum(nil)),
|
||||
)
|
||||
}
|
||||
|
||||
// signingKey makes a signing key by HMAC'ing the timestamp
|
||||
// using a client secret as the key.
|
||||
func signingKey(clientSecret string, timestamp string) []byte {
|
||||
h := hmac.New(sha256.New, []byte(clientSecret))
|
||||
h.Write([]byte(timestamp))
|
||||
key := make([]byte, base64.StdEncoding.EncodedLen(32))
|
||||
base64.StdEncoding.Encode(key, h.Sum(nil))
|
||||
return key
|
||||
}
|
||||
|
||||
// PurgeTags constructs and dispatches a request to purge a batch of Tags.
|
||||
func (cpc *CachePurgeClient) PurgeTags(tags []string) error {
|
||||
purgeReq := v3PurgeRequest{
|
||||
Objects: tags,
|
||||
}
|
||||
endpoint := fmt.Sprintf("%s%s%s", cpc.apiEndpoint, v3PurgeTagPath, cpc.v3Network)
|
||||
return cpc.authedRequest(endpoint, purgeReq)
|
||||
}
|
||||
|
||||
// purgeURLs constructs and dispatches a request to purge a batch of URLs.
|
||||
func (cpc *CachePurgeClient) purgeURLs(urls []string) error {
|
||||
purgeReq := v3PurgeRequest{
|
||||
Objects: urls,
|
||||
}
|
||||
endpoint := fmt.Sprintf("%s%s%s", cpc.apiEndpoint, v3PurgePath, cpc.v3Network)
|
||||
return cpc.authedRequest(endpoint, purgeReq)
|
||||
}
|
||||
|
||||
// authedRequest POSTs the JSON marshaled purge request to the provided endpoint
|
||||
// along with an Akamai authorization header.
|
||||
func (cpc *CachePurgeClient) authedRequest(endpoint string, body v3PurgeRequest) error {
|
||||
reqBody, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", err, errFatal)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", endpoint, bytes.NewBuffer(reqBody))
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", err, errFatal)
|
||||
}
|
||||
|
||||
endpointURL, err := url.Parse(endpoint)
|
||||
if err != nil {
|
||||
return fmt.Errorf("while parsing %q as URL: %s: %w", endpoint, err, errFatal)
|
||||
}
|
||||
|
||||
authorization := cpc.makeAuthHeader(reqBody, endpointURL.Path, core.RandomString(16))
|
||||
req.Header.Set("Authorization", authorization)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
cpc.log.Debugf("POSTing to endpoint %q (header %q) (body %q)", endpoint, authorization, reqBody)
|
||||
|
||||
start := cpc.clk.Now()
|
||||
resp, err := cpc.client.Do(req)
|
||||
cpc.purgeLatency.Observe(cpc.clk.Since(start).Seconds())
|
||||
if err != nil {
|
||||
return fmt.Errorf("while POSTing to endpoint %q: %w", endpointURL, err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.Body == nil {
|
||||
return fmt.Errorf("response body was empty from URL %q", resp.Request.URL)
|
||||
}
|
||||
|
||||
respBody, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Success for a request to purge a URL or Cache tag is 'HTTP 201'.
|
||||
// https://techdocs.akamai.com/purge-cache/reference/delete-url
|
||||
// https://techdocs.akamai.com/purge-cache/reference/delete-tag
|
||||
if resp.StatusCode != http.StatusCreated {
|
||||
switch resp.StatusCode {
|
||||
// https://techdocs.akamai.com/purge-cache/reference/403
|
||||
case http.StatusForbidden:
|
||||
return fmt.Errorf("client not authorized to make requests for URL %q: %w", resp.Request.URL, errFatal)
|
||||
|
||||
// https://techdocs.akamai.com/purge-cache/reference/504
|
||||
case http.StatusGatewayTimeout:
|
||||
return fmt.Errorf("server timed out, got HTTP %d (body %q) for URL %q", resp.StatusCode, respBody, resp.Request.URL)
|
||||
|
||||
// https://techdocs.akamai.com/purge-cache/reference/429
|
||||
case http.StatusTooManyRequests:
|
||||
return fmt.Errorf("exceeded request count rate limit, got HTTP %d (body %q) for URL %q", resp.StatusCode, respBody, resp.Request.URL)
|
||||
|
||||
// https://techdocs.akamai.com/purge-cache/reference/413
|
||||
case http.StatusRequestEntityTooLarge:
|
||||
return fmt.Errorf("exceeded request size rate limit, got HTTP %d (body %q) for URL %q", resp.StatusCode, respBody, resp.Request.URL)
|
||||
default:
|
||||
return fmt.Errorf("received HTTP %d (body %q) for URL %q", resp.StatusCode, respBody, resp.Request.URL)
|
||||
}
|
||||
}
|
||||
|
||||
var purgeInfo purgeResponse
|
||||
err = json.Unmarshal(respBody, &purgeInfo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("while unmarshalling body %q from URL %q as JSON: %w", respBody, resp.Request.URL, err)
|
||||
}
|
||||
|
||||
// Ensure the unmarshaled body concurs with the status of the response
|
||||
// received.
|
||||
if purgeInfo.HTTPStatus != http.StatusCreated {
|
||||
if purgeInfo.HTTPStatus == http.StatusForbidden {
|
||||
return fmt.Errorf("client not authorized to make requests to URL %q: %w", resp.Request.URL, errFatal)
|
||||
}
|
||||
return fmt.Errorf("unmarshaled HTTP %d (body %q) from URL %q", purgeInfo.HTTPStatus, respBody, resp.Request.URL)
|
||||
}
|
||||
|
||||
cpc.log.AuditInfof("Purge request sent successfully (ID %s) (body %s). Purge expected in %ds",
|
||||
purgeInfo.PurgeID, reqBody, purgeInfo.EstimatedSeconds)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Purge dispatches the provided URLs in a request to the Akamai Fast-Purge API.
|
||||
// The request will be attempted cpc.retries number of times before giving up
|
||||
// and returning ErrAllRetriesFailed.
|
||||
func (cpc *CachePurgeClient) Purge(urls []string) error {
|
||||
successful := false
|
||||
for i := range cpc.retries + 1 {
|
||||
cpc.clk.Sleep(core.RetryBackoff(i, cpc.retryBackoff, time.Minute, 1.3))
|
||||
|
||||
err := cpc.purgeURLs(urls)
|
||||
if err != nil {
|
||||
if errors.Is(err, errFatal) {
|
||||
cpc.purges.WithLabelValues("fatal failure").Inc()
|
||||
return err
|
||||
}
|
||||
cpc.log.AuditErrf("Akamai cache purge failed, retrying: %s", err)
|
||||
cpc.purges.WithLabelValues("retryable failure").Inc()
|
||||
continue
|
||||
}
|
||||
successful = true
|
||||
break
|
||||
}
|
||||
|
||||
if !successful {
|
||||
cpc.purges.WithLabelValues("fatal failure").Inc()
|
||||
return ErrAllRetriesFailed
|
||||
}
|
||||
|
||||
cpc.purges.WithLabelValues("success").Inc()
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckSignature is exported for use in tests and akamai-test-srv.
|
||||
func CheckSignature(secret string, url string, r *http.Request, body []byte) error {
|
||||
bodyHash := sha256.Sum256(body)
|
||||
bodyHashB64 := base64.StdEncoding.EncodeToString(bodyHash[:])
|
||||
|
||||
authorization := r.Header.Get("Authorization")
|
||||
authValues := make(map[string]string)
|
||||
for _, v := range strings.Split(authorization, ";") {
|
||||
splitValue := strings.Split(v, "=")
|
||||
authValues[splitValue[0]] = splitValue[1]
|
||||
}
|
||||
headerTimestamp := authValues["timestamp"]
|
||||
splitHeader := strings.Split(authorization, "signature=")
|
||||
shortenedHeader, signature := splitHeader[0], splitHeader[1]
|
||||
hostPort := strings.Split(url, "://")[1]
|
||||
h := hmac.New(sha256.New, signingKey(secret, headerTimestamp))
|
||||
input := []byte(fmt.Sprintf("POST\thttp\t%s\t%s\t\t%s\t%s",
|
||||
hostPort,
|
||||
r.URL.Path,
|
||||
bodyHashB64,
|
||||
shortenedHeader,
|
||||
))
|
||||
h.Write(input)
|
||||
expectedSignature := base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||
if signature != expectedSignature {
|
||||
return fmt.Errorf("expected signature %q, got %q in %q",
|
||||
signature, authorization, expectedSignature)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func reverseBytes(b []byte) []byte {
|
||||
for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
|
||||
b[i], b[j] = b[j], b[i]
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// makeOCSPCacheURLs constructs the 3 URLs associated with each cached OCSP
|
||||
// response.
|
||||
func makeOCSPCacheURLs(req []byte, ocspServer string) []string {
|
||||
hash := md5.Sum(req)
|
||||
encReq := base64.StdEncoding.EncodeToString(req)
|
||||
return []string{
|
||||
// POST Cache Key: the format of this entry is the URL that was POSTed
|
||||
// to with a query string with the parameter 'body-md5' and the value of
|
||||
// the first two uint32s in little endian order in hex of the MD5 hash
|
||||
// of the OCSP request body.
|
||||
//
|
||||
// There is limited public documentation of this feature. However, this
|
||||
// entry is what triggers the Akamai cache behavior that allows Akamai to
|
||||
// identify POST based OCSP for purging. For more information, see:
|
||||
// https://techdocs.akamai.com/property-mgr/reference/v2020-03-04-cachepost
|
||||
// https://techdocs.akamai.com/property-mgr/docs/cache-post-responses
|
||||
fmt.Sprintf("%s?body-md5=%x%x", ocspServer, reverseBytes(hash[0:4]), reverseBytes(hash[4:8])),
|
||||
|
||||
// URL (un-encoded): RFC 2560 and RFC 5019 state OCSP GET URLs 'MUST
|
||||
// properly url-encode the base64 encoded' request but a large enough
|
||||
// portion of tools do not properly do this (~10% of GET requests we
|
||||
// receive) such that we must purge both the encoded and un-encoded
|
||||
// URLs.
|
||||
//
|
||||
// Due to Akamai proxy/cache behavior which collapses '//' -> '/' we also
|
||||
// collapse double slashes in the un-encoded URL so that we properly purge
|
||||
// what is stored in the cache.
|
||||
fmt.Sprintf("%s%s", ocspServer, strings.Replace(encReq, "//", "/", -1)),
|
||||
|
||||
// URL (encoded): this entry is the url-encoded GET URL used to request
|
||||
// OCSP as specified in RFC 2560 and RFC 5019.
|
||||
fmt.Sprintf("%s%s", ocspServer, url.QueryEscape(encReq)),
|
||||
}
|
||||
}
|
||||
|
||||
// GeneratePurgeURLs generates akamai URLs that can be POSTed to in order to
|
||||
// purge akamai's cache of the corresponding OCSP responses. The URLs encode
|
||||
// the contents of the OCSP request, so this method constructs a full OCSP
|
||||
// request.
|
||||
func GeneratePurgeURLs(cert, issuer *x509.Certificate) ([]string, error) {
|
||||
req, err := ocsp.CreateRequest(cert, issuer, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create a GET and special Akamai POST style OCSP url for each endpoint in
|
||||
// cert.OCSPServer.
|
||||
urls := []string{}
|
||||
for _, ocspServer := range cert.OCSPServer {
|
||||
if !strings.HasSuffix(ocspServer, "/") {
|
||||
ocspServer += "/"
|
||||
}
|
||||
urls = append(urls, makeOCSPCacheURLs(req, ocspServer)...)
|
||||
}
|
||||
return urls, nil
|
||||
}
|
||||
|
|
@ -1,275 +0,0 @@
|
|||
package akamai
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/jmhodges/clock"
|
||||
|
||||
blog "github.com/letsencrypt/boulder/log"
|
||||
"github.com/letsencrypt/boulder/metrics"
|
||||
"github.com/letsencrypt/boulder/test"
|
||||
)
|
||||
|
||||
func TestMakeAuthHeader(t *testing.T) {
|
||||
log := blog.NewMock()
|
||||
stats := metrics.NoopRegisterer
|
||||
cpc, err := NewCachePurgeClient(
|
||||
"https://akaa-baseurl-xxxxxxxxxxx-xxxxxxxxxxxxx.luna.akamaiapis.net",
|
||||
"akab-client-token-xxx-xxxxxxxxxxxxxxxx",
|
||||
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=",
|
||||
"akab-access-token-xxx-xxxxxxxxxxxxxxxx",
|
||||
"production",
|
||||
2,
|
||||
time.Second,
|
||||
log,
|
||||
stats,
|
||||
)
|
||||
test.AssertNotError(t, err, "Failed to create cache purge client")
|
||||
fc := clock.NewFake()
|
||||
cpc.clk = fc
|
||||
wantedTimestamp, err := time.Parse(timestampFormat, "20140321T19:34:21+0000")
|
||||
test.AssertNotError(t, err, "Failed to parse timestamp")
|
||||
fc.Set(wantedTimestamp)
|
||||
|
||||
expectedHeader := "EG1-HMAC-SHA256 client_token=akab-client-token-xxx-xxxxxxxxxxxxxxxx;access_token=akab-access-token-xxx-xxxxxxxxxxxxxxxx;timestamp=20140321T19:34:21+0000;nonce=nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx;signature=hXm4iCxtpN22m4cbZb4lVLW5rhX8Ca82vCFqXzSTPe4="
|
||||
authHeader := cpc.makeAuthHeader(
|
||||
[]byte("datadatadatadatadatadatadatadata"),
|
||||
"/testapi/v1/t3",
|
||||
"nonce-xx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
|
||||
)
|
||||
test.AssertEquals(t, authHeader, expectedHeader)
|
||||
}
|
||||
|
||||
type akamaiServer struct {
|
||||
responseCode int
|
||||
*httptest.Server
|
||||
}
|
||||
|
||||
func (as *akamaiServer) sendResponse(w http.ResponseWriter, resp purgeResponse) {
|
||||
respBytes, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to marshal response body: %s\n", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(as.responseCode)
|
||||
w.Write(respBytes)
|
||||
}
|
||||
|
||||
func (as *akamaiServer) purgeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var req struct {
|
||||
Objects []string
|
||||
}
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to read request body: %s\n", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
err = CheckSignature("secret", as.URL, r, body)
|
||||
if err != nil {
|
||||
fmt.Printf("Error checking signature: %s\n", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
err = json.Unmarshal(body, &req)
|
||||
if err != nil {
|
||||
fmt.Printf("Failed to unmarshal request body: %s\n", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
resp := purgeResponse{
|
||||
HTTPStatus: as.responseCode,
|
||||
Detail: "?",
|
||||
EstimatedSeconds: 10,
|
||||
PurgeID: "?",
|
||||
}
|
||||
|
||||
fmt.Println(r.URL.Path, v3PurgePath)
|
||||
if strings.HasPrefix(r.URL.Path, v3PurgePath) {
|
||||
for _, testURL := range req.Objects {
|
||||
if !strings.HasPrefix(testURL, "http://") {
|
||||
resp.HTTPStatus = http.StatusForbidden
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
as.sendResponse(w, resp)
|
||||
}
|
||||
func newAkamaiServer(code int) *akamaiServer {
|
||||
m := http.NewServeMux()
|
||||
as := akamaiServer{
|
||||
responseCode: code,
|
||||
Server: httptest.NewServer(m),
|
||||
}
|
||||
m.HandleFunc(v3PurgePath, as.purgeHandler)
|
||||
m.HandleFunc(v3PurgeTagPath, as.purgeHandler)
|
||||
return &as
|
||||
}
|
||||
|
||||
// TestV3Purge tests the Akamai CCU v3 purge API
|
||||
func TestV3Purge(t *testing.T) {
|
||||
as := newAkamaiServer(http.StatusCreated)
|
||||
defer as.Close()
|
||||
|
||||
// Client is a purge client with a "production" v3Network parameter
|
||||
client, err := NewCachePurgeClient(
|
||||
as.URL,
|
||||
"token",
|
||||
"secret",
|
||||
"accessToken",
|
||||
"production",
|
||||
3,
|
||||
time.Second,
|
||||
blog.NewMock(),
|
||||
metrics.NoopRegisterer,
|
||||
)
|
||||
test.AssertNotError(t, err, "Failed to create CachePurgeClient")
|
||||
client.clk = clock.NewFake()
|
||||
|
||||
err = client.Purge([]string{"http://test.com"})
|
||||
test.AssertNotError(t, err, "Purge failed; expected 201 response")
|
||||
|
||||
started := client.clk.Now()
|
||||
as.responseCode = http.StatusInternalServerError
|
||||
err = client.Purge([]string{"http://test.com"})
|
||||
test.AssertError(t, err, "Purge succeeded; expected 500 response")
|
||||
t.Log(client.clk.Since(started))
|
||||
// Given 3 retries, with a retry interval of 1 second, a growth factor of 1.3,
|
||||
// and a jitter of 0.2, the minimum amount of elapsed time is:
|
||||
// (1 * 0.8) + (1 * 1.3 * 0.8) + (1 * 1.3 * 1.3 * 0.8) = 3.192s
|
||||
test.Assert(t, client.clk.Since(started) > (time.Second*3), "Retries should've taken at least 3.192 seconds")
|
||||
|
||||
started = client.clk.Now()
|
||||
as.responseCode = http.StatusCreated
|
||||
err = client.Purge([]string{"http:/test.com"})
|
||||
test.AssertError(t, err, "Purge succeeded; expected a 403 response from malformed URL")
|
||||
test.Assert(t, client.clk.Since(started) < time.Second, "Purge should've failed out immediately")
|
||||
}
|
||||
|
||||
func TestPurgeTags(t *testing.T) {
|
||||
as := newAkamaiServer(http.StatusCreated)
|
||||
defer as.Close()
|
||||
|
||||
// Client is a purge client with a "production" v3Network parameter
|
||||
client, err := NewCachePurgeClient(
|
||||
as.URL,
|
||||
"token",
|
||||
"secret",
|
||||
"accessToken",
|
||||
"production",
|
||||
3,
|
||||
time.Second,
|
||||
blog.NewMock(),
|
||||
metrics.NoopRegisterer,
|
||||
)
|
||||
test.AssertNotError(t, err, "Failed to create CachePurgeClient")
|
||||
fc := clock.NewFake()
|
||||
client.clk = fc
|
||||
|
||||
err = client.PurgeTags([]string{"ff"})
|
||||
test.AssertNotError(t, err, "Purge failed; expected response 201")
|
||||
|
||||
as.responseCode = http.StatusForbidden
|
||||
err = client.PurgeTags([]string{"http://test.com"})
|
||||
test.AssertError(t, err, "Purge succeeded; expected Forbidden response")
|
||||
}
|
||||
|
||||
func TestNewCachePurgeClient(t *testing.T) {
|
||||
// Creating a new cache purge client with an invalid "network" parameter should error
|
||||
_, err := NewCachePurgeClient(
|
||||
"http://127.0.0.1:9000/",
|
||||
"token",
|
||||
"secret",
|
||||
"accessToken",
|
||||
"fake",
|
||||
3,
|
||||
time.Second,
|
||||
blog.NewMock(),
|
||||
metrics.NoopRegisterer,
|
||||
)
|
||||
test.AssertError(t, err, "NewCachePurgeClient with invalid network parameter didn't error")
|
||||
|
||||
// Creating a new cache purge client with a valid "network" parameter shouldn't error
|
||||
_, err = NewCachePurgeClient(
|
||||
"http://127.0.0.1:9000/",
|
||||
"token",
|
||||
"secret",
|
||||
"accessToken",
|
||||
"staging",
|
||||
3,
|
||||
time.Second,
|
||||
blog.NewMock(),
|
||||
metrics.NoopRegisterer,
|
||||
)
|
||||
test.AssertNotError(t, err, "NewCachePurgeClient with valid network parameter errored")
|
||||
|
||||
// Creating a new cache purge client with an invalid server URL parameter should error
|
||||
_, err = NewCachePurgeClient(
|
||||
"h&ttp://whatever",
|
||||
"token",
|
||||
"secret",
|
||||
"accessToken",
|
||||
"staging",
|
||||
3,
|
||||
time.Second,
|
||||
blog.NewMock(),
|
||||
metrics.NoopRegisterer,
|
||||
)
|
||||
test.AssertError(t, err, "NewCachePurgeClient with invalid server url parameter didn't error")
|
||||
}
|
||||
|
||||
func TestBigBatchPurge(t *testing.T) {
|
||||
log := blog.NewMock()
|
||||
|
||||
as := newAkamaiServer(http.StatusCreated)
|
||||
|
||||
client, err := NewCachePurgeClient(
|
||||
as.URL,
|
||||
"token",
|
||||
"secret",
|
||||
"accessToken",
|
||||
"production",
|
||||
3,
|
||||
time.Second,
|
||||
log,
|
||||
metrics.NoopRegisterer,
|
||||
)
|
||||
test.AssertNotError(t, err, "Failed to create CachePurgeClient")
|
||||
|
||||
var urls []string
|
||||
for i := range 250 {
|
||||
urls = append(urls, fmt.Sprintf("http://test.com/%d", i))
|
||||
}
|
||||
|
||||
err = client.Purge(urls)
|
||||
test.AssertNotError(t, err, "Purge failed.")
|
||||
}
|
||||
|
||||
func TestReverseBytes(t *testing.T) {
|
||||
a := []byte{0, 1, 2, 3}
|
||||
test.AssertDeepEquals(t, reverseBytes(a), []byte{3, 2, 1, 0})
|
||||
}
|
||||
|
||||
func TestGenerateOCSPCacheKeys(t *testing.T) {
|
||||
der := []byte{105, 239, 255}
|
||||
test.AssertDeepEquals(
|
||||
t,
|
||||
makeOCSPCacheURLs(der, "ocsp.invalid/"),
|
||||
[]string{
|
||||
"ocsp.invalid/?body-md5=d6101198a9d9f1f6",
|
||||
"ocsp.invalid/ae/",
|
||||
"ocsp.invalid/ae%2F%2F",
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -1,137 +0,0 @@
|
|||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.5
|
||||
// protoc v3.20.1
|
||||
// source: akamai.proto
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type PurgeRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Urls []string `protobuf:"bytes,1,rep,name=urls,proto3" json:"urls,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *PurgeRequest) Reset() {
|
||||
*x = PurgeRequest{}
|
||||
mi := &file_akamai_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *PurgeRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*PurgeRequest) ProtoMessage() {}
|
||||
|
||||
func (x *PurgeRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_akamai_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use PurgeRequest.ProtoReflect.Descriptor instead.
|
||||
func (*PurgeRequest) Descriptor() ([]byte, []int) {
|
||||
return file_akamai_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *PurgeRequest) GetUrls() []string {
|
||||
if x != nil {
|
||||
return x.Urls
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_akamai_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_akamai_proto_rawDesc = string([]byte{
|
||||
0x0a, 0x0c, 0x61, 0x6b, 0x61, 0x6d, 0x61, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06,
|
||||
0x61, 0x6b, 0x61, 0x6d, 0x61, 0x69, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x22, 0x22, 0x0a, 0x0c, 0x50, 0x75, 0x72, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x72, 0x6c, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
|
||||
0x09, 0x52, 0x04, 0x75, 0x72, 0x6c, 0x73, 0x32, 0x47, 0x0a, 0x0c, 0x41, 0x6b, 0x61, 0x6d, 0x61,
|
||||
0x69, 0x50, 0x75, 0x72, 0x67, 0x65, 0x72, 0x12, 0x37, 0x0a, 0x05, 0x50, 0x75, 0x72, 0x67, 0x65,
|
||||
0x12, 0x14, 0x2e, 0x61, 0x6b, 0x61, 0x6d, 0x61, 0x69, 0x2e, 0x50, 0x75, 0x72, 0x67, 0x65, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00,
|
||||
0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c,
|
||||
0x65, 0x74, 0x73, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x2f, 0x62, 0x6f, 0x75, 0x6c, 0x64,
|
||||
0x65, 0x72, 0x2f, 0x61, 0x6b, 0x61, 0x6d, 0x61, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
})
|
||||
|
||||
var (
|
||||
file_akamai_proto_rawDescOnce sync.Once
|
||||
file_akamai_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_akamai_proto_rawDescGZIP() []byte {
|
||||
file_akamai_proto_rawDescOnce.Do(func() {
|
||||
file_akamai_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_akamai_proto_rawDesc), len(file_akamai_proto_rawDesc)))
|
||||
})
|
||||
return file_akamai_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_akamai_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
|
||||
var file_akamai_proto_goTypes = []any{
|
||||
(*PurgeRequest)(nil), // 0: akamai.PurgeRequest
|
||||
(*emptypb.Empty)(nil), // 1: google.protobuf.Empty
|
||||
}
|
||||
var file_akamai_proto_depIdxs = []int32{
|
||||
0, // 0: akamai.AkamaiPurger.Purge:input_type -> akamai.PurgeRequest
|
||||
1, // 1: akamai.AkamaiPurger.Purge:output_type -> google.protobuf.Empty
|
||||
1, // [1:2] is the sub-list for method output_type
|
||||
0, // [0:1] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_akamai_proto_init() }
|
||||
func file_akamai_proto_init() {
|
||||
if File_akamai_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_akamai_proto_rawDesc), len(file_akamai_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 1,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_akamai_proto_goTypes,
|
||||
DependencyIndexes: file_akamai_proto_depIdxs,
|
||||
MessageInfos: file_akamai_proto_msgTypes,
|
||||
}.Build()
|
||||
File_akamai_proto = out.File
|
||||
file_akamai_proto_goTypes = nil
|
||||
file_akamai_proto_depIdxs = nil
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package akamai;
|
||||
option go_package = "github.com/letsencrypt/boulder/akamai/proto";
|
||||
|
||||
import "google/protobuf/empty.proto";
|
||||
|
||||
service AkamaiPurger {
|
||||
rpc Purge(PurgeRequest) returns (google.protobuf.Empty) {}
|
||||
}
|
||||
|
||||
message PurgeRequest {
|
||||
repeated string urls = 1;
|
||||
}
|
||||
|
|
@ -1,122 +0,0 @@
|
|||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.5.1
|
||||
// - protoc v3.20.1
|
||||
// source: akamai.proto
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
AkamaiPurger_Purge_FullMethodName = "/akamai.AkamaiPurger/Purge"
|
||||
)
|
||||
|
||||
// AkamaiPurgerClient is the client API for AkamaiPurger service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type AkamaiPurgerClient interface {
|
||||
Purge(ctx context.Context, in *PurgeRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
|
||||
}
|
||||
|
||||
type akamaiPurgerClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewAkamaiPurgerClient(cc grpc.ClientConnInterface) AkamaiPurgerClient {
|
||||
return &akamaiPurgerClient{cc}
|
||||
}
|
||||
|
||||
func (c *akamaiPurgerClient) Purge(ctx context.Context, in *PurgeRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(emptypb.Empty)
|
||||
err := c.cc.Invoke(ctx, AkamaiPurger_Purge_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// AkamaiPurgerServer is the server API for AkamaiPurger service.
|
||||
// All implementations must embed UnimplementedAkamaiPurgerServer
|
||||
// for forward compatibility.
|
||||
type AkamaiPurgerServer interface {
|
||||
Purge(context.Context, *PurgeRequest) (*emptypb.Empty, error)
|
||||
mustEmbedUnimplementedAkamaiPurgerServer()
|
||||
}
|
||||
|
||||
// UnimplementedAkamaiPurgerServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedAkamaiPurgerServer struct{}
|
||||
|
||||
func (UnimplementedAkamaiPurgerServer) Purge(context.Context, *PurgeRequest) (*emptypb.Empty, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Purge not implemented")
|
||||
}
|
||||
func (UnimplementedAkamaiPurgerServer) mustEmbedUnimplementedAkamaiPurgerServer() {}
|
||||
func (UnimplementedAkamaiPurgerServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeAkamaiPurgerServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to AkamaiPurgerServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeAkamaiPurgerServer interface {
|
||||
mustEmbedUnimplementedAkamaiPurgerServer()
|
||||
}
|
||||
|
||||
func RegisterAkamaiPurgerServer(s grpc.ServiceRegistrar, srv AkamaiPurgerServer) {
|
||||
// If the following call pancis, it indicates UnimplementedAkamaiPurgerServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&AkamaiPurger_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _AkamaiPurger_Purge_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(PurgeRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(AkamaiPurgerServer).Purge(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: AkamaiPurger_Purge_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(AkamaiPurgerServer).Purge(ctx, req.(*PurgeRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// AkamaiPurger_ServiceDesc is the grpc.ServiceDesc for AkamaiPurger service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var AkamaiPurger_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "akamai.AkamaiPurger",
|
||||
HandlerType: (*AkamaiPurgerServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Purge",
|
||||
Handler: _AkamaiPurger_Purge_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "akamai.proto",
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
package allowlist
|
||||
|
||||
import (
|
||||
"github.com/letsencrypt/boulder/strictyaml"
|
||||
)
|
||||
|
||||
// List holds a unique collection of items of type T. Membership can be checked
|
||||
// by calling the Contains method.
|
||||
type List[T comparable] struct {
|
||||
members map[T]struct{}
|
||||
}
|
||||
|
||||
// NewList returns a *List[T] populated with the provided members of type T. All
|
||||
// duplicate entries are ignored, ensuring uniqueness.
|
||||
func NewList[T comparable](members []T) *List[T] {
|
||||
l := &List[T]{members: make(map[T]struct{})}
|
||||
for _, m := range members {
|
||||
l.members[m] = struct{}{}
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// NewFromYAML reads a YAML sequence of values of type T and returns a *List[T]
|
||||
// containing those values. If data is empty, an empty (deny all) list is
|
||||
// returned. If data cannot be parsed, an error is returned.
|
||||
func NewFromYAML[T comparable](data []byte) (*List[T], error) {
|
||||
if len(data) == 0 {
|
||||
return NewList([]T{}), nil
|
||||
}
|
||||
|
||||
var entries []T
|
||||
err := strictyaml.Unmarshal(data, &entries)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return NewList(entries), nil
|
||||
}
|
||||
|
||||
// Contains reports whether the provided entry is a member of the list.
|
||||
func (l *List[T]) Contains(entry T) bool {
|
||||
_, ok := l.members[entry]
|
||||
return ok
|
||||
}
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
package allowlist
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewFromYAML(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
yamlData string
|
||||
check []string
|
||||
expectAnswers []bool
|
||||
expectErr bool
|
||||
}{
|
||||
{
|
||||
name: "valid YAML",
|
||||
yamlData: "- oak\n- maple\n- cherry",
|
||||
check: []string{"oak", "walnut", "maple", "cherry"},
|
||||
expectAnswers: []bool{true, false, true, true},
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "empty YAML",
|
||||
yamlData: "",
|
||||
check: []string{"oak", "walnut", "maple", "cherry"},
|
||||
expectAnswers: []bool{false, false, false, false},
|
||||
expectErr: false,
|
||||
},
|
||||
{
|
||||
name: "invalid YAML",
|
||||
yamlData: "{ invalid_yaml",
|
||||
check: []string{},
|
||||
expectAnswers: []bool{},
|
||||
expectErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
list, err := NewFromYAML[string]([]byte(tt.yamlData))
|
||||
if (err != nil) != tt.expectErr {
|
||||
t.Fatalf("NewFromYAML() error = %v, expectErr = %v", err, tt.expectErr)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
for i, item := range tt.check {
|
||||
got := list.Contains(item)
|
||||
if got != tt.expectAnswers[i] {
|
||||
t.Errorf("Contains(%q) got %v, want %v", item, got, tt.expectAnswers[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewList(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
members []string
|
||||
check []string
|
||||
expectAnswers []bool
|
||||
}{
|
||||
{
|
||||
name: "unique members",
|
||||
members: []string{"oak", "maple", "cherry"},
|
||||
check: []string{"oak", "walnut", "maple", "cherry"},
|
||||
expectAnswers: []bool{true, false, true, true},
|
||||
},
|
||||
{
|
||||
name: "duplicate members",
|
||||
members: []string{"oak", "maple", "cherry", "oak"},
|
||||
check: []string{"oak", "walnut", "maple", "cherry"},
|
||||
expectAnswers: []bool{true, false, true, true},
|
||||
},
|
||||
{
|
||||
name: "nil list",
|
||||
members: nil,
|
||||
check: []string{"oak", "walnut", "maple", "cherry"},
|
||||
expectAnswers: []bool{false, false, false, false},
|
||||
},
|
||||
{
|
||||
name: "empty list",
|
||||
members: []string{},
|
||||
check: []string{"oak", "walnut", "maple", "cherry"},
|
||||
expectAnswers: []bool{false, false, false, false},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
list := NewList[string](tt.members)
|
||||
for i, item := range tt.check {
|
||||
got := list.Contains(item)
|
||||
if got != tt.expectAnswers[i] {
|
||||
t.Errorf("Contains(%q) got %v, want %v", item, got, tt.expectAnswers[i])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,586 +0,0 @@
|
|||
package bdns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/jmhodges/clock"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"github.com/letsencrypt/boulder/iana"
|
||||
blog "github.com/letsencrypt/boulder/log"
|
||||
"github.com/letsencrypt/boulder/metrics"
|
||||
)
|
||||
|
||||
// ResolverAddrs contains DNS resolver(s) that were chosen to perform a
|
||||
// validation request or CAA recheck. A ResolverAddr will be in the form of
|
||||
// host:port, A:host:port, or AAAA:host:port depending on which type of lookup
|
||||
// was done.
|
||||
type ResolverAddrs []string
|
||||
|
||||
// Client queries for DNS records
|
||||
type Client interface {
|
||||
LookupTXT(context.Context, string) (txts []string, resolver ResolverAddrs, err error)
|
||||
LookupHost(context.Context, string) ([]netip.Addr, ResolverAddrs, error)
|
||||
LookupCAA(context.Context, string) ([]*dns.CAA, string, ResolverAddrs, error)
|
||||
}
|
||||
|
||||
// impl represents a client that talks to an external resolver
|
||||
type impl struct {
|
||||
dnsClient exchanger
|
||||
servers ServerProvider
|
||||
allowRestrictedAddresses bool
|
||||
maxTries int
|
||||
clk clock.Clock
|
||||
log blog.Logger
|
||||
|
||||
queryTime *prometheus.HistogramVec
|
||||
totalLookupTime *prometheus.HistogramVec
|
||||
timeoutCounter *prometheus.CounterVec
|
||||
idMismatchCounter *prometheus.CounterVec
|
||||
}
|
||||
|
||||
var _ Client = &impl{}
|
||||
|
||||
type exchanger interface {
|
||||
Exchange(m *dns.Msg, a string) (*dns.Msg, time.Duration, error)
|
||||
}
|
||||
|
||||
// New constructs a new DNS resolver object that utilizes the
|
||||
// provided list of DNS servers for resolution.
|
||||
//
|
||||
// `tlsConfig` is the configuration used for outbound DoH queries,
|
||||
// if applicable.
|
||||
func New(
|
||||
readTimeout time.Duration,
|
||||
servers ServerProvider,
|
||||
stats prometheus.Registerer,
|
||||
clk clock.Clock,
|
||||
maxTries int,
|
||||
userAgent string,
|
||||
log blog.Logger,
|
||||
tlsConfig *tls.Config,
|
||||
) Client {
|
||||
var client exchanger
|
||||
|
||||
// Clone the default transport because it comes with various settings
|
||||
// that we like, which are different from the zero value of an
|
||||
// `http.Transport`.
|
||||
transport := http.DefaultTransport.(*http.Transport).Clone()
|
||||
transport.TLSClientConfig = tlsConfig
|
||||
// The default transport already sets this field, but it isn't
|
||||
// documented that it will always be set. Set it again to be sure,
|
||||
// because Unbound will reject non-HTTP/2 DoH requests.
|
||||
transport.ForceAttemptHTTP2 = true
|
||||
client = &dohExchanger{
|
||||
clk: clk,
|
||||
hc: http.Client{
|
||||
Timeout: readTimeout,
|
||||
Transport: transport,
|
||||
},
|
||||
userAgent: userAgent,
|
||||
}
|
||||
|
||||
queryTime := prometheus.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "dns_query_time",
|
||||
Help: "Time taken to perform a DNS query",
|
||||
Buckets: metrics.InternetFacingBuckets,
|
||||
},
|
||||
[]string{"qtype", "result", "resolver"},
|
||||
)
|
||||
totalLookupTime := prometheus.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: "dns_total_lookup_time",
|
||||
Help: "Time taken to perform a DNS lookup, including all retried queries",
|
||||
Buckets: metrics.InternetFacingBuckets,
|
||||
},
|
||||
[]string{"qtype", "result", "retries", "resolver"},
|
||||
)
|
||||
timeoutCounter := prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "dns_timeout",
|
||||
Help: "Counter of various types of DNS query timeouts",
|
||||
},
|
||||
[]string{"qtype", "type", "resolver", "isTLD"},
|
||||
)
|
||||
idMismatchCounter := prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "dns_id_mismatch",
|
||||
Help: "Counter of DNS ErrId errors sliced by query type and resolver",
|
||||
},
|
||||
[]string{"qtype", "resolver"},
|
||||
)
|
||||
stats.MustRegister(queryTime, totalLookupTime, timeoutCounter, idMismatchCounter)
|
||||
return &impl{
|
||||
dnsClient: client,
|
||||
servers: servers,
|
||||
allowRestrictedAddresses: false,
|
||||
maxTries: maxTries,
|
||||
clk: clk,
|
||||
queryTime: queryTime,
|
||||
totalLookupTime: totalLookupTime,
|
||||
timeoutCounter: timeoutCounter,
|
||||
idMismatchCounter: idMismatchCounter,
|
||||
log: log,
|
||||
}
|
||||
}
|
||||
|
||||
// NewTest constructs a new DNS resolver object that utilizes the
|
||||
// provided list of DNS servers for resolution and will allow loopback addresses.
|
||||
// This constructor should *only* be called from tests (unit or integration).
|
||||
func NewTest(
|
||||
readTimeout time.Duration,
|
||||
servers ServerProvider,
|
||||
stats prometheus.Registerer,
|
||||
clk clock.Clock,
|
||||
maxTries int,
|
||||
userAgent string,
|
||||
log blog.Logger,
|
||||
tlsConfig *tls.Config,
|
||||
) Client {
|
||||
resolver := New(readTimeout, servers, stats, clk, maxTries, userAgent, log, tlsConfig)
|
||||
resolver.(*impl).allowRestrictedAddresses = true
|
||||
return resolver
|
||||
}
|
||||
|
||||
// exchangeOne performs a single DNS exchange with a randomly chosen server
|
||||
// out of the server list, returning the response, time, and error (if any).
|
||||
// We assume that the upstream resolver requests and validates DNSSEC records
|
||||
// itself.
|
||||
func (dnsClient *impl) exchangeOne(ctx context.Context, hostname string, qtype uint16) (resp *dns.Msg, resolver string, err error) {
|
||||
m := new(dns.Msg)
|
||||
// Set question type
|
||||
m.SetQuestion(dns.Fqdn(hostname), qtype)
|
||||
// Set the AD bit in the query header so that the resolver knows that
|
||||
// we are interested in this bit in the response header. If this isn't
|
||||
// set the AD bit in the response is useless (RFC 6840 Section 5.7).
|
||||
// This has no security implications, it simply allows us to gather
|
||||
// metrics about the percentage of responses that are secured with
|
||||
// DNSSEC.
|
||||
m.AuthenticatedData = true
|
||||
// Tell the resolver that we're willing to receive responses up to 4096 bytes.
|
||||
// This happens sometimes when there are a very large number of CAA records
|
||||
// present.
|
||||
m.SetEdns0(4096, false)
|
||||
|
||||
servers, err := dnsClient.servers.Addrs()
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("failed to list DNS servers: %w", err)
|
||||
}
|
||||
chosenServerIndex := 0
|
||||
chosenServer := servers[chosenServerIndex]
|
||||
resolver = chosenServer
|
||||
|
||||
// Strip off the IP address part of the server address because
|
||||
// we talk to the same server on multiple ports, and don't want
|
||||
// to blow up the cardinality.
|
||||
chosenServerIP, _, err := net.SplitHostPort(chosenServer)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
start := dnsClient.clk.Now()
|
||||
client := dnsClient.dnsClient
|
||||
qtypeStr := dns.TypeToString[qtype]
|
||||
tries := 1
|
||||
defer func() {
|
||||
result := "failed"
|
||||
if resp != nil {
|
||||
result = dns.RcodeToString[resp.Rcode]
|
||||
}
|
||||
dnsClient.totalLookupTime.With(prometheus.Labels{
|
||||
"qtype": qtypeStr,
|
||||
"result": result,
|
||||
"retries": strconv.Itoa(tries),
|
||||
"resolver": chosenServerIP,
|
||||
}).Observe(dnsClient.clk.Since(start).Seconds())
|
||||
}()
|
||||
for {
|
||||
ch := make(chan dnsResp, 1)
|
||||
|
||||
// Strip off the IP address part of the server address because
|
||||
// we talk to the same server on multiple ports, and don't want
|
||||
// to blow up the cardinality.
|
||||
// Note: validateServerAddress() has already checked net.SplitHostPort()
|
||||
// and ensures that chosenServer can't be a bare port, e.g. ":1337"
|
||||
chosenServerIP, _, err = net.SplitHostPort(chosenServer)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
rsp, rtt, err := client.Exchange(m, chosenServer)
|
||||
result := "failed"
|
||||
if rsp != nil {
|
||||
result = dns.RcodeToString[rsp.Rcode]
|
||||
}
|
||||
if err != nil {
|
||||
logDNSError(dnsClient.log, chosenServer, hostname, m, rsp, err)
|
||||
if err == dns.ErrId {
|
||||
dnsClient.idMismatchCounter.With(prometheus.Labels{
|
||||
"qtype": qtypeStr,
|
||||
"resolver": chosenServerIP,
|
||||
}).Inc()
|
||||
}
|
||||
}
|
||||
dnsClient.queryTime.With(prometheus.Labels{
|
||||
"qtype": qtypeStr,
|
||||
"result": result,
|
||||
"resolver": chosenServerIP,
|
||||
}).Observe(rtt.Seconds())
|
||||
ch <- dnsResp{m: rsp, err: err}
|
||||
}()
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if ctx.Err() == context.DeadlineExceeded {
|
||||
dnsClient.timeoutCounter.With(prometheus.Labels{
|
||||
"qtype": qtypeStr,
|
||||
"type": "deadline exceeded",
|
||||
"resolver": chosenServerIP,
|
||||
"isTLD": isTLD(hostname),
|
||||
}).Inc()
|
||||
} else if ctx.Err() == context.Canceled {
|
||||
dnsClient.timeoutCounter.With(prometheus.Labels{
|
||||
"qtype": qtypeStr,
|
||||
"type": "canceled",
|
||||
"resolver": chosenServerIP,
|
||||
"isTLD": isTLD(hostname),
|
||||
}).Inc()
|
||||
} else {
|
||||
dnsClient.timeoutCounter.With(prometheus.Labels{
|
||||
"qtype": qtypeStr,
|
||||
"type": "unknown",
|
||||
"resolver": chosenServerIP,
|
||||
}).Inc()
|
||||
}
|
||||
err = ctx.Err()
|
||||
return
|
||||
case r := <-ch:
|
||||
if r.err != nil {
|
||||
var isRetryable bool
|
||||
// According to the http package documentation, retryable
|
||||
// errors emitted by the http package are of type *url.Error.
|
||||
var urlErr *url.Error
|
||||
isRetryable = errors.As(r.err, &urlErr) && urlErr.Temporary()
|
||||
hasRetriesLeft := tries < dnsClient.maxTries
|
||||
if isRetryable && hasRetriesLeft {
|
||||
tries++
|
||||
// Chose a new server to retry the query with by incrementing the
|
||||
// chosen server index modulo the number of servers. This ensures that
|
||||
// if one dns server isn't available we retry with the next in the
|
||||
// list.
|
||||
chosenServerIndex = (chosenServerIndex + 1) % len(servers)
|
||||
chosenServer = servers[chosenServerIndex]
|
||||
resolver = chosenServer
|
||||
continue
|
||||
} else if isRetryable && !hasRetriesLeft {
|
||||
dnsClient.timeoutCounter.With(prometheus.Labels{
|
||||
"qtype": qtypeStr,
|
||||
"type": "out of retries",
|
||||
"resolver": chosenServerIP,
|
||||
"isTLD": isTLD(hostname),
|
||||
}).Inc()
|
||||
}
|
||||
}
|
||||
resp, err = r.m, r.err
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// isTLD returns a simplified view of whether something is a TLD: does it have
|
||||
// any dots in it? This returns true or false as a string, and is meant solely
|
||||
// for Prometheus metrics.
|
||||
func isTLD(hostname string) string {
|
||||
if strings.Contains(hostname, ".") {
|
||||
return "false"
|
||||
} else {
|
||||
return "true"
|
||||
}
|
||||
}
|
||||
|
||||
type dnsResp struct {
|
||||
m *dns.Msg
|
||||
err error
|
||||
}
|
||||
|
||||
// LookupTXT sends a DNS query to find all TXT records associated with
|
||||
// the provided hostname which it returns along with the returned
|
||||
// DNS authority section.
|
||||
func (dnsClient *impl) LookupTXT(ctx context.Context, hostname string) ([]string, ResolverAddrs, error) {
|
||||
var txt []string
|
||||
dnsType := dns.TypeTXT
|
||||
r, resolver, err := dnsClient.exchangeOne(ctx, hostname, dnsType)
|
||||
errWrap := wrapErr(dnsType, hostname, r, err)
|
||||
if errWrap != nil {
|
||||
return nil, ResolverAddrs{resolver}, errWrap
|
||||
}
|
||||
|
||||
for _, answer := range r.Answer {
|
||||
if answer.Header().Rrtype == dnsType {
|
||||
if txtRec, ok := answer.(*dns.TXT); ok {
|
||||
txt = append(txt, strings.Join(txtRec.Txt, ""))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return txt, ResolverAddrs{resolver}, err
|
||||
}
|
||||
|
||||
func (dnsClient *impl) lookupIP(ctx context.Context, hostname string, ipType uint16) ([]dns.RR, string, error) {
|
||||
resp, resolver, err := dnsClient.exchangeOne(ctx, hostname, ipType)
|
||||
switch ipType {
|
||||
case dns.TypeA:
|
||||
if resolver != "" {
|
||||
resolver = "A:" + resolver
|
||||
}
|
||||
case dns.TypeAAAA:
|
||||
if resolver != "" {
|
||||
resolver = "AAAA:" + resolver
|
||||
}
|
||||
}
|
||||
errWrap := wrapErr(ipType, hostname, resp, err)
|
||||
if errWrap != nil {
|
||||
return nil, resolver, errWrap
|
||||
}
|
||||
return resp.Answer, resolver, nil
|
||||
}
|
||||
|
||||
// LookupHost sends a DNS query to find all A and AAAA records associated with
|
||||
// the provided hostname. This method assumes that the external resolver will
|
||||
// chase CNAME/DNAME aliases and return relevant records. It will retry
|
||||
// requests in the case of temporary network errors. It returns an error if
|
||||
// both the A and AAAA lookups fail or are empty, but succeeds otherwise.
|
||||
func (dnsClient *impl) LookupHost(ctx context.Context, hostname string) ([]netip.Addr, ResolverAddrs, error) {
|
||||
var recordsA, recordsAAAA []dns.RR
|
||||
var errA, errAAAA error
|
||||
var resolverA, resolverAAAA string
|
||||
var wg sync.WaitGroup
|
||||
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
recordsA, resolverA, errA = dnsClient.lookupIP(ctx, hostname, dns.TypeA)
|
||||
}()
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
recordsAAAA, resolverAAAA, errAAAA = dnsClient.lookupIP(ctx, hostname, dns.TypeAAAA)
|
||||
}()
|
||||
wg.Wait()
|
||||
|
||||
resolvers := ResolverAddrs{resolverA, resolverAAAA}
|
||||
resolvers = slices.DeleteFunc(resolvers, func(a string) bool {
|
||||
return a == ""
|
||||
})
|
||||
|
||||
var addrsA []netip.Addr
|
||||
if errA == nil {
|
||||
for _, answer := range recordsA {
|
||||
if answer.Header().Rrtype == dns.TypeA {
|
||||
a, ok := answer.(*dns.A)
|
||||
if ok && a.A.To4() != nil {
|
||||
netIP, ok := netip.AddrFromSlice(a.A)
|
||||
if ok && (iana.IsReservedAddr(netIP) == nil || dnsClient.allowRestrictedAddresses) {
|
||||
addrsA = append(addrsA, netIP)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(addrsA) == 0 {
|
||||
errA = fmt.Errorf("no valid A records found for %s", hostname)
|
||||
}
|
||||
}
|
||||
|
||||
var addrsAAAA []netip.Addr
|
||||
if errAAAA == nil {
|
||||
for _, answer := range recordsAAAA {
|
||||
if answer.Header().Rrtype == dns.TypeAAAA {
|
||||
aaaa, ok := answer.(*dns.AAAA)
|
||||
if ok && aaaa.AAAA.To16() != nil {
|
||||
netIP, ok := netip.AddrFromSlice(aaaa.AAAA)
|
||||
if ok && (iana.IsReservedAddr(netIP) == nil || dnsClient.allowRestrictedAddresses) {
|
||||
addrsAAAA = append(addrsAAAA, netIP)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(addrsAAAA) == 0 {
|
||||
errAAAA = fmt.Errorf("no valid AAAA records found for %s", hostname)
|
||||
}
|
||||
}
|
||||
|
||||
if errA != nil && errAAAA != nil {
|
||||
// Construct a new error from both underlying errors. We can only use %w for
|
||||
// one of them, because the go error unwrapping protocol doesn't support
|
||||
// branching. We don't use ProblemDetails and SubProblemDetails here, because
|
||||
// this error will get wrapped in a DNSError and further munged by higher
|
||||
// layers in the stack.
|
||||
return nil, resolvers, fmt.Errorf("%w; %s", errA, errAAAA)
|
||||
}
|
||||
|
||||
return append(addrsA, addrsAAAA...), resolvers, nil
|
||||
}
|
||||
|
||||
// LookupCAA sends a DNS query to find all CAA records associated with
|
||||
// the provided hostname and the complete dig-style RR `response`. This
|
||||
// response is quite verbose, however it's only populated when the CAA
|
||||
// response is non-empty.
|
||||
func (dnsClient *impl) LookupCAA(ctx context.Context, hostname string) ([]*dns.CAA, string, ResolverAddrs, error) {
|
||||
dnsType := dns.TypeCAA
|
||||
r, resolver, err := dnsClient.exchangeOne(ctx, hostname, dnsType)
|
||||
|
||||
// Special case: when checking CAA for non-TLD names, treat NXDOMAIN as a
|
||||
// successful response containing an empty set of records. This can come up in
|
||||
// situations where records were provisioned for validation (e.g. TXT records
|
||||
// for DNS-01 challenge) and then removed after validation but before CAA
|
||||
// rechecking. But allow NXDOMAIN for TLDs to fall through to the error code
|
||||
// below, so we don't issue for gTLDs that have been removed by ICANN.
|
||||
if err == nil && r.Rcode == dns.RcodeNameError && strings.Contains(hostname, ".") {
|
||||
return nil, "", ResolverAddrs{resolver}, nil
|
||||
}
|
||||
|
||||
errWrap := wrapErr(dnsType, hostname, r, err)
|
||||
if errWrap != nil {
|
||||
return nil, "", ResolverAddrs{resolver}, errWrap
|
||||
}
|
||||
|
||||
var CAAs []*dns.CAA
|
||||
for _, answer := range r.Answer {
|
||||
if caaR, ok := answer.(*dns.CAA); ok {
|
||||
CAAs = append(CAAs, caaR)
|
||||
}
|
||||
}
|
||||
var response string
|
||||
if len(CAAs) > 0 {
|
||||
response = r.String()
|
||||
}
|
||||
return CAAs, response, ResolverAddrs{resolver}, nil
|
||||
}
|
||||
|
||||
// logDNSError logs the provided err result from making a query for hostname to
|
||||
// the chosenServer. If the err is a `dns.ErrId` instance then the Base64
|
||||
// encoded bytes of the query (and if not-nil, the response) in wire format
|
||||
// is logged as well. This function is called from exchangeOne only for the case
|
||||
// where an error occurs querying a hostname that indicates a problem between
|
||||
// the VA and the chosenServer.
|
||||
func logDNSError(
|
||||
logger blog.Logger,
|
||||
chosenServer string,
|
||||
hostname string,
|
||||
msg, resp *dns.Msg,
|
||||
underlying error) {
|
||||
// We don't expect logDNSError to be called with a nil msg or err but
|
||||
// if it happens return early. We allow resp to be nil.
|
||||
if msg == nil || len(msg.Question) == 0 || underlying == nil {
|
||||
return
|
||||
}
|
||||
queryType := dns.TypeToString[msg.Question[0].Qtype]
|
||||
|
||||
// If the error indicates there was a query/response ID mismatch then we want
|
||||
// to log more detail.
|
||||
if underlying == dns.ErrId {
|
||||
packedMsgBytes, err := msg.Pack()
|
||||
if err != nil {
|
||||
logger.Errf("logDNSError failed to pack msg: %v", err)
|
||||
return
|
||||
}
|
||||
encodedMsg := base64.StdEncoding.EncodeToString(packedMsgBytes)
|
||||
|
||||
var encodedResp string
|
||||
var respQname string
|
||||
if resp != nil {
|
||||
packedRespBytes, err := resp.Pack()
|
||||
if err != nil {
|
||||
logger.Errf("logDNSError failed to pack resp: %v", err)
|
||||
return
|
||||
}
|
||||
encodedResp = base64.StdEncoding.EncodeToString(packedRespBytes)
|
||||
if len(resp.Answer) > 0 && resp.Answer[0].Header() != nil {
|
||||
respQname = resp.Answer[0].Header().Name
|
||||
}
|
||||
}
|
||||
|
||||
logger.Infof(
|
||||
"logDNSError ID mismatch chosenServer=[%s] hostname=[%s] respHostname=[%s] queryType=[%s] msg=[%s] resp=[%s] err=[%s]",
|
||||
chosenServer,
|
||||
hostname,
|
||||
respQname,
|
||||
queryType,
|
||||
encodedMsg,
|
||||
encodedResp,
|
||||
underlying)
|
||||
} else {
|
||||
// Otherwise log a general DNS error
|
||||
logger.Infof("logDNSError chosenServer=[%s] hostname=[%s] queryType=[%s] err=[%s]",
|
||||
chosenServer,
|
||||
hostname,
|
||||
queryType,
|
||||
underlying)
|
||||
}
|
||||
}
|
||||
|
||||
type dohExchanger struct {
|
||||
clk clock.Clock
|
||||
hc http.Client
|
||||
userAgent string
|
||||
}
|
||||
|
||||
// Exchange sends a DoH query to the provided DoH server and returns the response.
|
||||
func (d *dohExchanger) Exchange(query *dns.Msg, server string) (*dns.Msg, time.Duration, error) {
|
||||
q, err := query.Pack()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// The default Unbound URL template
|
||||
url := fmt.Sprintf("https://%s/dns-query", server)
|
||||
req, err := http.NewRequest("POST", url, strings.NewReader(string(q)))
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/dns-message")
|
||||
req.Header.Set("Accept", "application/dns-message")
|
||||
if len(d.userAgent) > 0 {
|
||||
req.Header.Set("User-Agent", d.userAgent)
|
||||
}
|
||||
|
||||
start := d.clk.Now()
|
||||
resp, err := d.hc.Do(req)
|
||||
if err != nil {
|
||||
return nil, d.clk.Since(start), err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, d.clk.Since(start), fmt.Errorf("doh: http status %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
b, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, d.clk.Since(start), fmt.Errorf("doh: reading response body: %w", err)
|
||||
}
|
||||
|
||||
response := new(dns.Msg)
|
||||
err = response.Unpack(b)
|
||||
if err != nil {
|
||||
return nil, d.clk.Since(start), fmt.Errorf("doh: unpacking response: %w", err)
|
||||
}
|
||||
|
||||
return response, d.clk.Since(start), nil
|
||||
}
|
||||
|
|
@ -1,891 +0,0 @@
|
|||
package bdns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/netip"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/jmhodges/clock"
|
||||
"github.com/miekg/dns"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
blog "github.com/letsencrypt/boulder/log"
|
||||
"github.com/letsencrypt/boulder/metrics"
|
||||
"github.com/letsencrypt/boulder/test"
|
||||
)
|
||||
|
||||
const dnsLoopbackAddr = "127.0.0.1:4053"
|
||||
|
||||
func mockDNSQuery(w http.ResponseWriter, httpReq *http.Request) {
|
||||
if httpReq.Header.Get("Content-Type") != "application/dns-message" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
fmt.Fprintf(w, "client didn't send Content-Type: application/dns-message")
|
||||
}
|
||||
if httpReq.Header.Get("Accept") != "application/dns-message" {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
fmt.Fprintf(w, "client didn't accept Content-Type: application/dns-message")
|
||||
}
|
||||
|
||||
requestBody, err := io.ReadAll(httpReq.Body)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
fmt.Fprintf(w, "reading body: %s", err)
|
||||
}
|
||||
httpReq.Body.Close()
|
||||
|
||||
r := new(dns.Msg)
|
||||
err = r.Unpack(requestBody)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
fmt.Fprintf(w, "unpacking request: %s", err)
|
||||
}
|
||||
|
||||
m := new(dns.Msg)
|
||||
m.SetReply(r)
|
||||
m.Compress = false
|
||||
|
||||
appendAnswer := func(rr dns.RR) {
|
||||
m.Answer = append(m.Answer, rr)
|
||||
}
|
||||
for _, q := range r.Question {
|
||||
q.Name = strings.ToLower(q.Name)
|
||||
if q.Name == "servfail.com." || q.Name == "servfailexception.example.com" {
|
||||
m.Rcode = dns.RcodeServerFailure
|
||||
break
|
||||
}
|
||||
switch q.Qtype {
|
||||
case dns.TypeSOA:
|
||||
record := new(dns.SOA)
|
||||
record.Hdr = dns.RR_Header{Name: "letsencrypt.org.", Rrtype: dns.TypeSOA, Class: dns.ClassINET, Ttl: 0}
|
||||
record.Ns = "ns.letsencrypt.org."
|
||||
record.Mbox = "master.letsencrypt.org."
|
||||
record.Serial = 1
|
||||
record.Refresh = 1
|
||||
record.Retry = 1
|
||||
record.Expire = 1
|
||||
record.Minttl = 1
|
||||
appendAnswer(record)
|
||||
case dns.TypeAAAA:
|
||||
if q.Name == "v6.letsencrypt.org." {
|
||||
record := new(dns.AAAA)
|
||||
record.Hdr = dns.RR_Header{Name: "v6.letsencrypt.org.", Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 0}
|
||||
record.AAAA = net.ParseIP("2602:80a:6000:abad:cafe::1")
|
||||
appendAnswer(record)
|
||||
}
|
||||
if q.Name == "dualstack.letsencrypt.org." {
|
||||
record := new(dns.AAAA)
|
||||
record.Hdr = dns.RR_Header{Name: "dualstack.letsencrypt.org.", Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 0}
|
||||
record.AAAA = net.ParseIP("2602:80a:6000:abad:cafe::1")
|
||||
appendAnswer(record)
|
||||
}
|
||||
if q.Name == "v4error.letsencrypt.org." {
|
||||
record := new(dns.AAAA)
|
||||
record.Hdr = dns.RR_Header{Name: "v4error.letsencrypt.org.", Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 0}
|
||||
record.AAAA = net.ParseIP("2602:80a:6000:abad:cafe::1")
|
||||
appendAnswer(record)
|
||||
}
|
||||
if q.Name == "v6error.letsencrypt.org." {
|
||||
m.SetRcode(r, dns.RcodeNotImplemented)
|
||||
}
|
||||
if q.Name == "nxdomain.letsencrypt.org." {
|
||||
m.SetRcode(r, dns.RcodeNameError)
|
||||
}
|
||||
if q.Name == "dualstackerror.letsencrypt.org." {
|
||||
m.SetRcode(r, dns.RcodeNotImplemented)
|
||||
}
|
||||
case dns.TypeA:
|
||||
if q.Name == "cps.letsencrypt.org." {
|
||||
record := new(dns.A)
|
||||
record.Hdr = dns.RR_Header{Name: "cps.letsencrypt.org.", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0}
|
||||
record.A = net.ParseIP("64.112.117.1")
|
||||
appendAnswer(record)
|
||||
}
|
||||
if q.Name == "dualstack.letsencrypt.org." {
|
||||
record := new(dns.A)
|
||||
record.Hdr = dns.RR_Header{Name: "dualstack.letsencrypt.org.", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0}
|
||||
record.A = net.ParseIP("64.112.117.1")
|
||||
appendAnswer(record)
|
||||
}
|
||||
if q.Name == "v6error.letsencrypt.org." {
|
||||
record := new(dns.A)
|
||||
record.Hdr = dns.RR_Header{Name: "dualstack.letsencrypt.org.", Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0}
|
||||
record.A = net.ParseIP("64.112.117.1")
|
||||
appendAnswer(record)
|
||||
}
|
||||
if q.Name == "v4error.letsencrypt.org." {
|
||||
m.SetRcode(r, dns.RcodeNotImplemented)
|
||||
}
|
||||
if q.Name == "nxdomain.letsencrypt.org." {
|
||||
m.SetRcode(r, dns.RcodeNameError)
|
||||
}
|
||||
if q.Name == "dualstackerror.letsencrypt.org." {
|
||||
m.SetRcode(r, dns.RcodeRefused)
|
||||
}
|
||||
case dns.TypeCNAME:
|
||||
if q.Name == "cname.letsencrypt.org." {
|
||||
record := new(dns.CNAME)
|
||||
record.Hdr = dns.RR_Header{Name: "cname.letsencrypt.org.", Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: 30}
|
||||
record.Target = "cps.letsencrypt.org."
|
||||
appendAnswer(record)
|
||||
}
|
||||
if q.Name == "cname.example.com." {
|
||||
record := new(dns.CNAME)
|
||||
record.Hdr = dns.RR_Header{Name: "cname.example.com.", Rrtype: dns.TypeCNAME, Class: dns.ClassINET, Ttl: 30}
|
||||
record.Target = "CAA.example.com."
|
||||
appendAnswer(record)
|
||||
}
|
||||
case dns.TypeDNAME:
|
||||
if q.Name == "dname.letsencrypt.org." {
|
||||
record := new(dns.DNAME)
|
||||
record.Hdr = dns.RR_Header{Name: "dname.letsencrypt.org.", Rrtype: dns.TypeDNAME, Class: dns.ClassINET, Ttl: 30}
|
||||
record.Target = "cps.letsencrypt.org."
|
||||
appendAnswer(record)
|
||||
}
|
||||
case dns.TypeCAA:
|
||||
if q.Name == "bracewel.net." || q.Name == "caa.example.com." {
|
||||
record := new(dns.CAA)
|
||||
record.Hdr = dns.RR_Header{Name: q.Name, Rrtype: dns.TypeCAA, Class: dns.ClassINET, Ttl: 0}
|
||||
record.Tag = "issue"
|
||||
record.Value = "letsencrypt.org"
|
||||
record.Flag = 1
|
||||
appendAnswer(record)
|
||||
}
|
||||
if q.Name == "cname.example.com." {
|
||||
record := new(dns.CAA)
|
||||
record.Hdr = dns.RR_Header{Name: "caa.example.com.", Rrtype: dns.TypeCAA, Class: dns.ClassINET, Ttl: 0}
|
||||
record.Tag = "issue"
|
||||
record.Value = "letsencrypt.org"
|
||||
record.Flag = 1
|
||||
appendAnswer(record)
|
||||
}
|
||||
if q.Name == "gonetld." {
|
||||
m.SetRcode(r, dns.RcodeNameError)
|
||||
}
|
||||
case dns.TypeTXT:
|
||||
if q.Name == "split-txt.letsencrypt.org." {
|
||||
record := new(dns.TXT)
|
||||
record.Hdr = dns.RR_Header{Name: "split-txt.letsencrypt.org.", Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0}
|
||||
record.Txt = []string{"a", "b", "c"}
|
||||
appendAnswer(record)
|
||||
} else {
|
||||
auth := new(dns.SOA)
|
||||
auth.Hdr = dns.RR_Header{Name: "letsencrypt.org.", Rrtype: dns.TypeSOA, Class: dns.ClassINET, Ttl: 0}
|
||||
auth.Ns = "ns.letsencrypt.org."
|
||||
auth.Mbox = "master.letsencrypt.org."
|
||||
auth.Serial = 1
|
||||
auth.Refresh = 1
|
||||
auth.Retry = 1
|
||||
auth.Expire = 1
|
||||
auth.Minttl = 1
|
||||
m.Ns = append(m.Ns, auth)
|
||||
}
|
||||
if q.Name == "nxdomain.letsencrypt.org." {
|
||||
m.SetRcode(r, dns.RcodeNameError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body, err := m.Pack()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "packing reply: %s\n", err)
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/dns-message")
|
||||
_, err = w.Write(body)
|
||||
if err != nil {
|
||||
panic(err) // running tests, so panic is OK
|
||||
}
|
||||
}
|
||||
|
||||
func serveLoopResolver(stopChan chan bool) {
|
||||
m := http.NewServeMux()
|
||||
m.HandleFunc("/dns-query", mockDNSQuery)
|
||||
httpServer := &http.Server{
|
||||
Addr: dnsLoopbackAddr,
|
||||
Handler: m,
|
||||
ReadTimeout: time.Second,
|
||||
WriteTimeout: time.Second,
|
||||
}
|
||||
go func() {
|
||||
cert := "../test/certs/ipki/localhost/cert.pem"
|
||||
key := "../test/certs/ipki/localhost/key.pem"
|
||||
err := httpServer.ListenAndServeTLS(cert, key)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
<-stopChan
|
||||
err := httpServer.Shutdown(context.Background())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func pollServer() {
|
||||
backoff := 200 * time.Millisecond
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
ticker := time.NewTicker(backoff)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
fmt.Fprintln(os.Stderr, "Timeout reached while testing for the dns server to come up")
|
||||
os.Exit(1)
|
||||
case <-ticker.C:
|
||||
conn, _ := dns.DialTimeout("udp", dnsLoopbackAddr, backoff)
|
||||
if conn != nil {
|
||||
_ = conn.Close()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// tlsConfig is used for the TLS config of client instances that talk to the
|
||||
// DoH server set up in TestMain.
|
||||
var tlsConfig *tls.Config
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
root, err := os.ReadFile("../test/certs/ipki/minica.pem")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
pool := x509.NewCertPool()
|
||||
pool.AppendCertsFromPEM(root)
|
||||
tlsConfig = &tls.Config{
|
||||
RootCAs: pool,
|
||||
}
|
||||
|
||||
stop := make(chan bool, 1)
|
||||
serveLoopResolver(stop)
|
||||
pollServer()
|
||||
ret := m.Run()
|
||||
stop <- true
|
||||
os.Exit(ret)
|
||||
}
|
||||
|
||||
func TestDNSNoServers(t *testing.T) {
|
||||
staticProvider, err := NewStaticProvider([]string{})
|
||||
test.AssertNotError(t, err, "Got error creating StaticProvider")
|
||||
|
||||
obj := New(time.Hour, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, "", blog.UseMock(), tlsConfig)
|
||||
|
||||
_, resolvers, err := obj.LookupHost(context.Background(), "letsencrypt.org")
|
||||
test.AssertEquals(t, len(resolvers), 0)
|
||||
test.AssertError(t, err, "No servers")
|
||||
|
||||
_, _, err = obj.LookupTXT(context.Background(), "letsencrypt.org")
|
||||
test.AssertError(t, err, "No servers")
|
||||
|
||||
_, _, _, err = obj.LookupCAA(context.Background(), "letsencrypt.org")
|
||||
test.AssertError(t, err, "No servers")
|
||||
}
|
||||
|
||||
func TestDNSOneServer(t *testing.T) {
|
||||
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
|
||||
test.AssertNotError(t, err, "Got error creating StaticProvider")
|
||||
|
||||
obj := New(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, "", blog.UseMock(), tlsConfig)
|
||||
|
||||
_, resolvers, err := obj.LookupHost(context.Background(), "cps.letsencrypt.org")
|
||||
test.AssertEquals(t, len(resolvers), 2)
|
||||
slices.Sort(resolvers)
|
||||
test.AssertDeepEquals(t, resolvers, ResolverAddrs{"A:127.0.0.1:4053", "AAAA:127.0.0.1:4053"})
|
||||
test.AssertNotError(t, err, "No message")
|
||||
}
|
||||
|
||||
func TestDNSDuplicateServers(t *testing.T) {
|
||||
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr, dnsLoopbackAddr})
|
||||
test.AssertNotError(t, err, "Got error creating StaticProvider")
|
||||
|
||||
obj := New(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, "", blog.UseMock(), tlsConfig)
|
||||
|
||||
_, resolvers, err := obj.LookupHost(context.Background(), "cps.letsencrypt.org")
|
||||
test.AssertEquals(t, len(resolvers), 2)
|
||||
slices.Sort(resolvers)
|
||||
test.AssertDeepEquals(t, resolvers, ResolverAddrs{"A:127.0.0.1:4053", "AAAA:127.0.0.1:4053"})
|
||||
test.AssertNotError(t, err, "No message")
|
||||
}
|
||||
|
||||
func TestDNSServFail(t *testing.T) {
|
||||
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
|
||||
test.AssertNotError(t, err, "Got error creating StaticProvider")
|
||||
|
||||
obj := New(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, "", blog.UseMock(), tlsConfig)
|
||||
bad := "servfail.com"
|
||||
|
||||
_, _, err = obj.LookupTXT(context.Background(), bad)
|
||||
test.AssertError(t, err, "LookupTXT didn't return an error")
|
||||
|
||||
_, _, err = obj.LookupHost(context.Background(), bad)
|
||||
test.AssertError(t, err, "LookupHost didn't return an error")
|
||||
|
||||
emptyCaa, _, _, err := obj.LookupCAA(context.Background(), bad)
|
||||
test.Assert(t, len(emptyCaa) == 0, "Query returned non-empty list of CAA records")
|
||||
test.AssertError(t, err, "LookupCAA should have returned an error")
|
||||
}
|
||||
|
||||
func TestDNSLookupTXT(t *testing.T) {
|
||||
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
|
||||
test.AssertNotError(t, err, "Got error creating StaticProvider")
|
||||
|
||||
obj := New(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, "", blog.UseMock(), tlsConfig)
|
||||
|
||||
a, _, err := obj.LookupTXT(context.Background(), "letsencrypt.org")
|
||||
t.Logf("A: %v", a)
|
||||
test.AssertNotError(t, err, "No message")
|
||||
|
||||
a, _, err = obj.LookupTXT(context.Background(), "split-txt.letsencrypt.org")
|
||||
t.Logf("A: %v ", a)
|
||||
test.AssertNotError(t, err, "No message")
|
||||
test.AssertEquals(t, len(a), 1)
|
||||
test.AssertEquals(t, a[0], "abc")
|
||||
}
|
||||
|
||||
// TODO(#8213): Convert this to a table test.
|
||||
func TestDNSLookupHost(t *testing.T) {
|
||||
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
|
||||
test.AssertNotError(t, err, "Got error creating StaticProvider")
|
||||
|
||||
obj := New(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, "", blog.UseMock(), tlsConfig)
|
||||
|
||||
ip, resolvers, err := obj.LookupHost(context.Background(), "servfail.com")
|
||||
t.Logf("servfail.com - IP: %s, Err: %s", ip, err)
|
||||
test.AssertError(t, err, "Server failure")
|
||||
test.Assert(t, len(ip) == 0, "Should not have IPs")
|
||||
slices.Sort(resolvers)
|
||||
test.AssertDeepEquals(t, resolvers, ResolverAddrs{"A:127.0.0.1:4053", "AAAA:127.0.0.1:4053"})
|
||||
|
||||
ip, resolvers, err = obj.LookupHost(context.Background(), "nonexistent.letsencrypt.org")
|
||||
t.Logf("nonexistent.letsencrypt.org - IP: %s, Err: %s", ip, err)
|
||||
test.AssertError(t, err, "No valid A or AAAA records should error")
|
||||
test.Assert(t, len(ip) == 0, "Should not have IPs")
|
||||
slices.Sort(resolvers)
|
||||
test.AssertDeepEquals(t, resolvers, ResolverAddrs{"A:127.0.0.1:4053", "AAAA:127.0.0.1:4053"})
|
||||
|
||||
// Single IPv4 address
|
||||
ip, resolvers, err = obj.LookupHost(context.Background(), "cps.letsencrypt.org")
|
||||
t.Logf("cps.letsencrypt.org - IP: %s, Err: %s", ip, err)
|
||||
test.AssertNotError(t, err, "Not an error to exist")
|
||||
test.Assert(t, len(ip) == 1, "Should have IP")
|
||||
slices.Sort(resolvers)
|
||||
test.AssertDeepEquals(t, resolvers, ResolverAddrs{"A:127.0.0.1:4053", "AAAA:127.0.0.1:4053"})
|
||||
ip, resolvers, err = obj.LookupHost(context.Background(), "cps.letsencrypt.org")
|
||||
t.Logf("cps.letsencrypt.org - IP: %s, Err: %s", ip, err)
|
||||
test.AssertNotError(t, err, "Not an error to exist")
|
||||
test.Assert(t, len(ip) == 1, "Should have IP")
|
||||
slices.Sort(resolvers)
|
||||
test.AssertDeepEquals(t, resolvers, ResolverAddrs{"A:127.0.0.1:4053", "AAAA:127.0.0.1:4053"})
|
||||
|
||||
// Single IPv6 address
|
||||
ip, resolvers, err = obj.LookupHost(context.Background(), "v6.letsencrypt.org")
|
||||
t.Logf("v6.letsencrypt.org - IP: %s, Err: %s", ip, err)
|
||||
test.AssertNotError(t, err, "Not an error to exist")
|
||||
test.Assert(t, len(ip) == 1, "Should not have IPs")
|
||||
slices.Sort(resolvers)
|
||||
test.AssertDeepEquals(t, resolvers, ResolverAddrs{"A:127.0.0.1:4053", "AAAA:127.0.0.1:4053"})
|
||||
|
||||
// Both IPv6 and IPv4 address
|
||||
ip, resolvers, err = obj.LookupHost(context.Background(), "dualstack.letsencrypt.org")
|
||||
t.Logf("dualstack.letsencrypt.org - IP: %s, Err: %s", ip, err)
|
||||
test.AssertNotError(t, err, "Not an error to exist")
|
||||
test.Assert(t, len(ip) == 2, "Should have 2 IPs")
|
||||
expected := netip.MustParseAddr("64.112.117.1")
|
||||
test.Assert(t, ip[0] == expected, "wrong ipv4 address")
|
||||
expected = netip.MustParseAddr("2602:80a:6000:abad:cafe::1")
|
||||
test.Assert(t, ip[1] == expected, "wrong ipv6 address")
|
||||
slices.Sort(resolvers)
|
||||
test.AssertDeepEquals(t, resolvers, ResolverAddrs{"A:127.0.0.1:4053", "AAAA:127.0.0.1:4053"})
|
||||
|
||||
// IPv6 error, IPv4 success
|
||||
ip, resolvers, err = obj.LookupHost(context.Background(), "v6error.letsencrypt.org")
|
||||
t.Logf("v6error.letsencrypt.org - IP: %s, Err: %s", ip, err)
|
||||
test.AssertNotError(t, err, "Not an error to exist")
|
||||
test.Assert(t, len(ip) == 1, "Should have 1 IP")
|
||||
expected = netip.MustParseAddr("64.112.117.1")
|
||||
test.Assert(t, ip[0] == expected, "wrong ipv4 address")
|
||||
slices.Sort(resolvers)
|
||||
test.AssertDeepEquals(t, resolvers, ResolverAddrs{"A:127.0.0.1:4053", "AAAA:127.0.0.1:4053"})
|
||||
|
||||
// IPv6 success, IPv4 error
|
||||
ip, resolvers, err = obj.LookupHost(context.Background(), "v4error.letsencrypt.org")
|
||||
t.Logf("v4error.letsencrypt.org - IP: %s, Err: %s", ip, err)
|
||||
test.AssertNotError(t, err, "Not an error to exist")
|
||||
test.Assert(t, len(ip) == 1, "Should have 1 IP")
|
||||
expected = netip.MustParseAddr("2602:80a:6000:abad:cafe::1")
|
||||
test.Assert(t, ip[0] == expected, "wrong ipv6 address")
|
||||
slices.Sort(resolvers)
|
||||
test.AssertDeepEquals(t, resolvers, ResolverAddrs{"A:127.0.0.1:4053", "AAAA:127.0.0.1:4053"})
|
||||
|
||||
// IPv6 error, IPv4 error
|
||||
// Should return both the IPv4 error (Refused) and the IPv6 error (NotImplemented)
|
||||
hostname := "dualstackerror.letsencrypt.org"
|
||||
ip, resolvers, err = obj.LookupHost(context.Background(), hostname)
|
||||
t.Logf("%s - IP: %s, Err: %s", hostname, ip, err)
|
||||
test.AssertError(t, err, "Should be an error")
|
||||
test.AssertContains(t, err.Error(), "REFUSED looking up A for")
|
||||
test.AssertContains(t, err.Error(), "NOTIMP looking up AAAA for")
|
||||
slices.Sort(resolvers)
|
||||
test.AssertDeepEquals(t, resolvers, ResolverAddrs{"A:127.0.0.1:4053", "AAAA:127.0.0.1:4053"})
|
||||
}
|
||||
|
||||
func TestDNSNXDOMAIN(t *testing.T) {
|
||||
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
|
||||
test.AssertNotError(t, err, "Got error creating StaticProvider")
|
||||
|
||||
obj := New(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, "", blog.UseMock(), tlsConfig)
|
||||
|
||||
hostname := "nxdomain.letsencrypt.org"
|
||||
_, _, err = obj.LookupHost(context.Background(), hostname)
|
||||
test.AssertContains(t, err.Error(), "NXDOMAIN looking up A for")
|
||||
test.AssertContains(t, err.Error(), "NXDOMAIN looking up AAAA for")
|
||||
|
||||
_, _, err = obj.LookupTXT(context.Background(), hostname)
|
||||
expected := Error{dns.TypeTXT, hostname, nil, dns.RcodeNameError, nil}
|
||||
test.AssertDeepEquals(t, err, expected)
|
||||
}
|
||||
|
||||
func TestDNSLookupCAA(t *testing.T) {
|
||||
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
|
||||
test.AssertNotError(t, err, "Got error creating StaticProvider")
|
||||
|
||||
obj := New(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 1, "", blog.UseMock(), tlsConfig)
|
||||
removeIDExp := regexp.MustCompile(" id: [[:digit:]]+")
|
||||
|
||||
caas, resp, resolvers, err := obj.LookupCAA(context.Background(), "bracewel.net")
|
||||
test.AssertNotError(t, err, "CAA lookup failed")
|
||||
test.Assert(t, len(caas) > 0, "Should have CAA records")
|
||||
test.AssertEquals(t, len(resolvers), 1)
|
||||
test.AssertDeepEquals(t, resolvers, ResolverAddrs{"127.0.0.1:4053"})
|
||||
expectedResp := `;; opcode: QUERY, status: NOERROR, id: XXXX
|
||||
;; flags: qr rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
|
||||
|
||||
;; QUESTION SECTION:
|
||||
;bracewel.net. IN CAA
|
||||
|
||||
;; ANSWER SECTION:
|
||||
bracewel.net. 0 IN CAA 1 issue "letsencrypt.org"
|
||||
`
|
||||
test.AssertEquals(t, removeIDExp.ReplaceAllString(resp, " id: XXXX"), expectedResp)
|
||||
|
||||
caas, resp, resolvers, err = obj.LookupCAA(context.Background(), "nonexistent.letsencrypt.org")
|
||||
test.AssertNotError(t, err, "CAA lookup failed")
|
||||
test.Assert(t, len(caas) == 0, "Shouldn't have CAA records")
|
||||
test.AssertEquals(t, resolvers[0], "127.0.0.1:4053")
|
||||
expectedResp = ""
|
||||
test.AssertEquals(t, resp, expectedResp)
|
||||
|
||||
caas, resp, resolvers, err = obj.LookupCAA(context.Background(), "nxdomain.letsencrypt.org")
|
||||
slices.Sort(resolvers)
|
||||
test.AssertNotError(t, err, "CAA lookup failed")
|
||||
test.Assert(t, len(caas) == 0, "Shouldn't have CAA records")
|
||||
test.AssertEquals(t, resolvers[0], "127.0.0.1:4053")
|
||||
expectedResp = ""
|
||||
test.AssertEquals(t, resp, expectedResp)
|
||||
|
||||
caas, resp, resolvers, err = obj.LookupCAA(context.Background(), "cname.example.com")
|
||||
test.AssertNotError(t, err, "CAA lookup failed")
|
||||
test.Assert(t, len(caas) > 0, "Should follow CNAME to find CAA")
|
||||
test.AssertEquals(t, resolvers[0], "127.0.0.1:4053")
|
||||
expectedResp = `;; opcode: QUERY, status: NOERROR, id: XXXX
|
||||
;; flags: qr rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
|
||||
|
||||
;; QUESTION SECTION:
|
||||
;cname.example.com. IN CAA
|
||||
|
||||
;; ANSWER SECTION:
|
||||
caa.example.com. 0 IN CAA 1 issue "letsencrypt.org"
|
||||
`
|
||||
test.AssertEquals(t, removeIDExp.ReplaceAllString(resp, " id: XXXX"), expectedResp)
|
||||
|
||||
_, _, resolvers, err = obj.LookupCAA(context.Background(), "gonetld")
|
||||
test.AssertError(t, err, "should fail for TLD NXDOMAIN")
|
||||
test.AssertContains(t, err.Error(), "NXDOMAIN")
|
||||
test.AssertEquals(t, resolvers[0], "127.0.0.1:4053")
|
||||
}
|
||||
|
||||
type testExchanger struct {
|
||||
sync.Mutex
|
||||
count int
|
||||
errs []error
|
||||
}
|
||||
|
||||
var errTooManyRequests = errors.New("too many requests")
|
||||
|
||||
func (te *testExchanger) Exchange(m *dns.Msg, a string) (*dns.Msg, time.Duration, error) {
|
||||
te.Lock()
|
||||
defer te.Unlock()
|
||||
msg := &dns.Msg{
|
||||
MsgHdr: dns.MsgHdr{Rcode: dns.RcodeSuccess},
|
||||
}
|
||||
if len(te.errs) <= te.count {
|
||||
return nil, 0, errTooManyRequests
|
||||
}
|
||||
err := te.errs[te.count]
|
||||
te.count++
|
||||
|
||||
return msg, 2 * time.Millisecond, err
|
||||
}
|
||||
|
||||
func TestRetry(t *testing.T) {
|
||||
isTempErr := &url.Error{Op: "read", Err: tempError(true)}
|
||||
nonTempErr := &url.Error{Op: "read", Err: tempError(false)}
|
||||
servFailError := errors.New("DNS problem: server failure at resolver looking up TXT for example.com")
|
||||
type testCase struct {
|
||||
name string
|
||||
maxTries int
|
||||
te *testExchanger
|
||||
expected error
|
||||
expectedCount int
|
||||
metricsAllRetries float64
|
||||
}
|
||||
tests := []*testCase{
|
||||
// The success on first try case
|
||||
{
|
||||
name: "success",
|
||||
maxTries: 3,
|
||||
te: &testExchanger{
|
||||
errs: []error{nil},
|
||||
},
|
||||
expected: nil,
|
||||
expectedCount: 1,
|
||||
},
|
||||
// Immediate non-OpError, error returns immediately
|
||||
{
|
||||
name: "non-operror",
|
||||
maxTries: 3,
|
||||
te: &testExchanger{
|
||||
errs: []error{errors.New("nope")},
|
||||
},
|
||||
expected: servFailError,
|
||||
expectedCount: 1,
|
||||
},
|
||||
// Temporary err, then non-OpError stops at two tries
|
||||
{
|
||||
name: "err-then-non-operror",
|
||||
maxTries: 3,
|
||||
te: &testExchanger{
|
||||
errs: []error{isTempErr, errors.New("nope")},
|
||||
},
|
||||
expected: servFailError,
|
||||
expectedCount: 2,
|
||||
},
|
||||
// Temporary error given always
|
||||
{
|
||||
name: "persistent-temp-error",
|
||||
maxTries: 3,
|
||||
te: &testExchanger{
|
||||
errs: []error{
|
||||
isTempErr,
|
||||
isTempErr,
|
||||
isTempErr,
|
||||
},
|
||||
},
|
||||
expected: servFailError,
|
||||
expectedCount: 3,
|
||||
metricsAllRetries: 1,
|
||||
},
|
||||
// Even with maxTries at 0, we should still let a single request go
|
||||
// through
|
||||
{
|
||||
name: "zero-maxtries",
|
||||
maxTries: 0,
|
||||
te: &testExchanger{
|
||||
errs: []error{nil},
|
||||
},
|
||||
expected: nil,
|
||||
expectedCount: 1,
|
||||
},
|
||||
// Temporary error given just once causes two tries
|
||||
{
|
||||
name: "single-temp-error",
|
||||
maxTries: 3,
|
||||
te: &testExchanger{
|
||||
errs: []error{
|
||||
isTempErr,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
expectedCount: 2,
|
||||
},
|
||||
// Temporary error given twice causes three tries
|
||||
{
|
||||
name: "double-temp-error",
|
||||
maxTries: 3,
|
||||
te: &testExchanger{
|
||||
errs: []error{
|
||||
isTempErr,
|
||||
isTempErr,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
expected: nil,
|
||||
expectedCount: 3,
|
||||
},
|
||||
// Temporary error given thrice causes three tries and fails
|
||||
{
|
||||
name: "triple-temp-error",
|
||||
maxTries: 3,
|
||||
te: &testExchanger{
|
||||
errs: []error{
|
||||
isTempErr,
|
||||
isTempErr,
|
||||
isTempErr,
|
||||
},
|
||||
},
|
||||
expected: servFailError,
|
||||
expectedCount: 3,
|
||||
metricsAllRetries: 1,
|
||||
},
|
||||
// temporary then non-Temporary error causes two retries
|
||||
{
|
||||
name: "temp-nontemp-error",
|
||||
maxTries: 3,
|
||||
te: &testExchanger{
|
||||
errs: []error{
|
||||
isTempErr,
|
||||
nonTempErr,
|
||||
},
|
||||
},
|
||||
expected: servFailError,
|
||||
expectedCount: 2,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
|
||||
test.AssertNotError(t, err, "Got error creating StaticProvider")
|
||||
|
||||
testClient := New(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), tc.maxTries, "", blog.UseMock(), tlsConfig)
|
||||
dr := testClient.(*impl)
|
||||
dr.dnsClient = tc.te
|
||||
_, _, err = dr.LookupTXT(context.Background(), "example.com")
|
||||
if err == errTooManyRequests {
|
||||
t.Errorf("#%d, sent more requests than the test case handles", i)
|
||||
}
|
||||
expectedErr := tc.expected
|
||||
if (expectedErr == nil && err != nil) ||
|
||||
(expectedErr != nil && err == nil) ||
|
||||
(expectedErr != nil && expectedErr.Error() != err.Error()) {
|
||||
t.Errorf("#%d, error, expected %v, got %v", i, expectedErr, err)
|
||||
}
|
||||
if tc.expectedCount != tc.te.count {
|
||||
t.Errorf("#%d, error, expectedCount %v, got %v", i, tc.expectedCount, tc.te.count)
|
||||
}
|
||||
if tc.metricsAllRetries > 0 {
|
||||
test.AssertMetricWithLabelsEquals(
|
||||
t, dr.timeoutCounter, prometheus.Labels{
|
||||
"qtype": "TXT",
|
||||
"type": "out of retries",
|
||||
"resolver": "127.0.0.1",
|
||||
"isTLD": "false",
|
||||
}, tc.metricsAllRetries)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
|
||||
test.AssertNotError(t, err, "Got error creating StaticProvider")
|
||||
|
||||
testClient := New(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 3, "", blog.UseMock(), tlsConfig)
|
||||
dr := testClient.(*impl)
|
||||
dr.dnsClient = &testExchanger{errs: []error{isTempErr, isTempErr, nil}}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
cancel()
|
||||
_, _, err = dr.LookupTXT(ctx, "example.com")
|
||||
if err == nil ||
|
||||
err.Error() != "DNS problem: query timed out (and was canceled) looking up TXT for example.com" {
|
||||
t.Errorf("expected %s, got %s", context.Canceled, err)
|
||||
}
|
||||
|
||||
dr.dnsClient = &testExchanger{errs: []error{isTempErr, isTempErr, nil}}
|
||||
ctx, cancel = context.WithTimeout(context.Background(), -10*time.Hour)
|
||||
defer cancel()
|
||||
_, _, err = dr.LookupTXT(ctx, "example.com")
|
||||
if err == nil ||
|
||||
err.Error() != "DNS problem: query timed out looking up TXT for example.com" {
|
||||
t.Errorf("expected %s, got %s", context.DeadlineExceeded, err)
|
||||
}
|
||||
|
||||
dr.dnsClient = &testExchanger{errs: []error{isTempErr, isTempErr, nil}}
|
||||
ctx, deadlineCancel := context.WithTimeout(context.Background(), -10*time.Hour)
|
||||
deadlineCancel()
|
||||
_, _, err = dr.LookupTXT(ctx, "example.com")
|
||||
if err == nil ||
|
||||
err.Error() != "DNS problem: query timed out looking up TXT for example.com" {
|
||||
t.Errorf("expected %s, got %s", context.DeadlineExceeded, err)
|
||||
}
|
||||
|
||||
test.AssertMetricWithLabelsEquals(
|
||||
t, dr.timeoutCounter, prometheus.Labels{
|
||||
"qtype": "TXT",
|
||||
"type": "canceled",
|
||||
"resolver": "127.0.0.1",
|
||||
}, 1)
|
||||
|
||||
test.AssertMetricWithLabelsEquals(
|
||||
t, dr.timeoutCounter, prometheus.Labels{
|
||||
"qtype": "TXT",
|
||||
"type": "deadline exceeded",
|
||||
"resolver": "127.0.0.1",
|
||||
}, 2)
|
||||
}
|
||||
|
||||
func TestIsTLD(t *testing.T) {
|
||||
if isTLD("com") != "true" {
|
||||
t.Errorf("expected 'com' to be a TLD, got %q", isTLD("com"))
|
||||
}
|
||||
if isTLD("example.com") != "false" {
|
||||
t.Errorf("expected 'example.com' to not a TLD, got %q", isTLD("example.com"))
|
||||
}
|
||||
}
|
||||
|
||||
type tempError bool
|
||||
|
||||
func (t tempError) Temporary() bool { return bool(t) }
|
||||
func (t tempError) Error() string { return fmt.Sprintf("Temporary: %t", t) }
|
||||
|
||||
// rotateFailureExchanger is a dns.Exchange implementation that tracks a count
|
||||
// of the number of calls to `Exchange` for a given address in the `lookups`
|
||||
// map. For all addresses in the `brokenAddresses` map, a retryable error is
|
||||
// returned from `Exchange`. This mock is used by `TestRotateServerOnErr`.
|
||||
type rotateFailureExchanger struct {
|
||||
sync.Mutex
|
||||
lookups map[string]int
|
||||
brokenAddresses map[string]bool
|
||||
}
|
||||
|
||||
// Exchange for rotateFailureExchanger tracks the `a` argument in `lookups` and
|
||||
// if present in `brokenAddresses`, returns a temporary error.
|
||||
func (e *rotateFailureExchanger) Exchange(m *dns.Msg, a string) (*dns.Msg, time.Duration, error) {
|
||||
e.Lock()
|
||||
defer e.Unlock()
|
||||
|
||||
// Track that exchange was called for the given server
|
||||
e.lookups[a]++
|
||||
|
||||
// If its a broken server, return a retryable error
|
||||
if e.brokenAddresses[a] {
|
||||
isTempErr := &url.Error{Op: "read", Err: tempError(true)}
|
||||
return nil, 2 * time.Millisecond, isTempErr
|
||||
}
|
||||
|
||||
return m, 2 * time.Millisecond, nil
|
||||
}
|
||||
|
||||
// TestRotateServerOnErr ensures that a retryable error returned from a DNS
|
||||
// server will result in the retry being performed against the next server in
|
||||
// the list.
|
||||
func TestRotateServerOnErr(t *testing.T) {
|
||||
// Configure three DNS servers
|
||||
dnsServers := []string{
|
||||
"a:53", "b:53", "[2606:4700:4700::1111]:53",
|
||||
}
|
||||
|
||||
// Set up a DNS client using these servers that will retry queries up to
|
||||
// a maximum of 5 times. It's important to choose a maxTries value >= the
|
||||
// number of dnsServers to ensure we always get around to trying the one
|
||||
// working server
|
||||
staticProvider, err := NewStaticProvider(dnsServers)
|
||||
test.AssertNotError(t, err, "Got error creating StaticProvider")
|
||||
|
||||
maxTries := 5
|
||||
client := New(time.Second*10, staticProvider, metrics.NoopRegisterer, clock.NewFake(), maxTries, "", blog.UseMock(), tlsConfig)
|
||||
|
||||
// Configure a mock exchanger that will always return a retryable error for
|
||||
// servers A and B. This will force server "[2606:4700:4700::1111]:53" to do
|
||||
// all the work once retries reach it.
|
||||
mock := &rotateFailureExchanger{
|
||||
brokenAddresses: map[string]bool{
|
||||
"a:53": true,
|
||||
"b:53": true,
|
||||
},
|
||||
lookups: make(map[string]int),
|
||||
}
|
||||
client.(*impl).dnsClient = mock
|
||||
|
||||
// Perform a bunch of lookups. We choose the initial server randomly. Any time
|
||||
// A or B is chosen there should be an error and a retry using the next server
|
||||
// in the list. Since we configured maxTries to be larger than the number of
|
||||
// servers *all* queries should eventually succeed by being retried against
|
||||
// server "[2606:4700:4700::1111]:53".
|
||||
for range maxTries * 2 {
|
||||
_, resolvers, err := client.LookupTXT(context.Background(), "example.com")
|
||||
test.AssertEquals(t, len(resolvers), 1)
|
||||
test.AssertEquals(t, resolvers[0], "[2606:4700:4700::1111]:53")
|
||||
// Any errors are unexpected - server "[2606:4700:4700::1111]:53" should
|
||||
// have responded without error.
|
||||
test.AssertNotError(t, err, "Expected no error from eventual retry with functional server")
|
||||
}
|
||||
|
||||
// We expect that the A and B servers had a non-zero number of lookups
|
||||
// attempted.
|
||||
test.Assert(t, mock.lookups["a:53"] > 0, "Expected A server to have non-zero lookup attempts")
|
||||
test.Assert(t, mock.lookups["b:53"] > 0, "Expected B server to have non-zero lookup attempts")
|
||||
|
||||
// We expect that the server "[2606:4700:4700::1111]:53" eventually served
|
||||
// all of the lookups attempted.
|
||||
test.AssertEquals(t, mock.lookups["[2606:4700:4700::1111]:53"], maxTries*2)
|
||||
|
||||
}
|
||||
|
||||
type mockTempURLError struct{}
|
||||
|
||||
func (m *mockTempURLError) Error() string { return "whoops, oh gosh" }
|
||||
func (m *mockTempURLError) Timeout() bool { return false }
|
||||
func (m *mockTempURLError) Temporary() bool { return true }
|
||||
|
||||
type dohAlwaysRetryExchanger struct {
|
||||
sync.Mutex
|
||||
err error
|
||||
}
|
||||
|
||||
func (dohE *dohAlwaysRetryExchanger) Exchange(m *dns.Msg, a string) (*dns.Msg, time.Duration, error) {
|
||||
dohE.Lock()
|
||||
defer dohE.Unlock()
|
||||
|
||||
tempURLerror := &url.Error{
|
||||
Op: "GET",
|
||||
URL: "https://example.com",
|
||||
Err: &mockTempURLError{},
|
||||
}
|
||||
|
||||
return nil, time.Second, tempURLerror
|
||||
}
|
||||
|
||||
func TestDOHMetric(t *testing.T) {
|
||||
staticProvider, err := NewStaticProvider([]string{dnsLoopbackAddr})
|
||||
test.AssertNotError(t, err, "Got error creating StaticProvider")
|
||||
|
||||
testClient := New(time.Second*11, staticProvider, metrics.NoopRegisterer, clock.NewFake(), 0, "", blog.UseMock(), tlsConfig)
|
||||
resolver := testClient.(*impl)
|
||||
resolver.dnsClient = &dohAlwaysRetryExchanger{err: &url.Error{Op: "read", Err: tempError(true)}}
|
||||
|
||||
// Starting out, we should count 0 "out of retries" errors.
|
||||
test.AssertMetricWithLabelsEquals(t, resolver.timeoutCounter, prometheus.Labels{"qtype": "None", "type": "out of retries", "resolver": "127.0.0.1", "isTLD": "false"}, 0)
|
||||
|
||||
// Trigger the error.
|
||||
_, _, _ = resolver.exchangeOne(context.Background(), "example.com", 0)
|
||||
|
||||
// Now, we should count 1 "out of retries" errors.
|
||||
test.AssertMetricWithLabelsEquals(t, resolver.timeoutCounter, prometheus.Labels{"qtype": "None", "type": "out of retries", "resolver": "127.0.0.1", "isTLD": "false"}, 1)
|
||||
}
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
package bdns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"os"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
|
||||
blog "github.com/letsencrypt/boulder/log"
|
||||
)
|
||||
|
||||
// MockClient is a mock
|
||||
type MockClient struct {
|
||||
Log blog.Logger
|
||||
}
|
||||
|
||||
// LookupTXT is a mock
|
||||
func (mock *MockClient) LookupTXT(_ context.Context, hostname string) ([]string, ResolverAddrs, error) {
|
||||
if hostname == "_acme-challenge.servfail.com" {
|
||||
return nil, ResolverAddrs{"MockClient"}, fmt.Errorf("SERVFAIL")
|
||||
}
|
||||
if hostname == "_acme-challenge.good-dns01.com" {
|
||||
// base64(sha256("LoqXcYV8q5ONbJQxbmR7SCTNo3tiAXDfowyjxAjEuX0"
|
||||
// + "." + "9jg46WB3rR_AHD-EBXdN7cBkH1WOu0tA3M9fm21mqTI"))
|
||||
// expected token + test account jwk thumbprint
|
||||
return []string{"LPsIwTo7o8BoG0-vjCyGQGBWSVIPxI-i_X336eUOQZo"}, ResolverAddrs{"MockClient"}, nil
|
||||
}
|
||||
if hostname == "_acme-challenge.wrong-dns01.com" {
|
||||
return []string{"a"}, ResolverAddrs{"MockClient"}, nil
|
||||
}
|
||||
if hostname == "_acme-challenge.wrong-many-dns01.com" {
|
||||
return []string{"a", "b", "c", "d", "e"}, ResolverAddrs{"MockClient"}, nil
|
||||
}
|
||||
if hostname == "_acme-challenge.long-dns01.com" {
|
||||
return []string{"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, ResolverAddrs{"MockClient"}, nil
|
||||
}
|
||||
if hostname == "_acme-challenge.no-authority-dns01.com" {
|
||||
// base64(sha256("LoqXcYV8q5ONbJQxbmR7SCTNo3tiAXDfowyjxAjEuX0"
|
||||
// + "." + "9jg46WB3rR_AHD-EBXdN7cBkH1WOu0tA3M9fm21mqTI"))
|
||||
// expected token + test account jwk thumbprint
|
||||
return []string{"LPsIwTo7o8BoG0-vjCyGQGBWSVIPxI-i_X336eUOQZo"}, ResolverAddrs{"MockClient"}, nil
|
||||
}
|
||||
// empty-txts.com always returns zero TXT records
|
||||
if hostname == "_acme-challenge.empty-txts.com" {
|
||||
return []string{}, ResolverAddrs{"MockClient"}, nil
|
||||
}
|
||||
return []string{"hostname"}, ResolverAddrs{"MockClient"}, nil
|
||||
}
|
||||
|
||||
// makeTimeoutError returns a a net.OpError for which Timeout() returns true.
|
||||
func makeTimeoutError() *net.OpError {
|
||||
return &net.OpError{
|
||||
Err: os.NewSyscallError("ugh timeout", timeoutError{}),
|
||||
}
|
||||
}
|
||||
|
||||
type timeoutError struct{}
|
||||
|
||||
func (t timeoutError) Error() string {
|
||||
return "so sloooow"
|
||||
}
|
||||
func (t timeoutError) Timeout() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// LookupHost is a mock
|
||||
func (mock *MockClient) LookupHost(_ context.Context, hostname string) ([]netip.Addr, ResolverAddrs, error) {
|
||||
if hostname == "always.invalid" ||
|
||||
hostname == "invalid.invalid" {
|
||||
return []netip.Addr{}, ResolverAddrs{"MockClient"}, nil
|
||||
}
|
||||
if hostname == "always.timeout" {
|
||||
return []netip.Addr{}, ResolverAddrs{"MockClient"}, &Error{dns.TypeA, "always.timeout", makeTimeoutError(), -1, nil}
|
||||
}
|
||||
if hostname == "always.error" {
|
||||
err := &net.OpError{
|
||||
Op: "read",
|
||||
Net: "udp",
|
||||
Err: errors.New("some net error"),
|
||||
}
|
||||
m := new(dns.Msg)
|
||||
m.SetQuestion(dns.Fqdn(hostname), dns.TypeA)
|
||||
m.AuthenticatedData = true
|
||||
m.SetEdns0(4096, false)
|
||||
logDNSError(mock.Log, "mock.server", hostname, m, nil, err)
|
||||
return []netip.Addr{}, ResolverAddrs{"MockClient"}, &Error{dns.TypeA, hostname, err, -1, nil}
|
||||
}
|
||||
if hostname == "id.mismatch" {
|
||||
err := dns.ErrId
|
||||
m := new(dns.Msg)
|
||||
m.SetQuestion(dns.Fqdn(hostname), dns.TypeA)
|
||||
m.AuthenticatedData = true
|
||||
m.SetEdns0(4096, false)
|
||||
r := new(dns.Msg)
|
||||
record := new(dns.A)
|
||||
record.Hdr = dns.RR_Header{Name: dns.Fqdn(hostname), Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 0}
|
||||
record.A = net.ParseIP("127.0.0.1")
|
||||
r.Answer = append(r.Answer, record)
|
||||
logDNSError(mock.Log, "mock.server", hostname, m, r, err)
|
||||
return []netip.Addr{}, ResolverAddrs{"MockClient"}, &Error{dns.TypeA, hostname, err, -1, nil}
|
||||
}
|
||||
// dual-homed host with an IPv6 and an IPv4 address
|
||||
if hostname == "ipv4.and.ipv6.localhost" {
|
||||
return []netip.Addr{
|
||||
netip.MustParseAddr("::1"),
|
||||
netip.MustParseAddr("127.0.0.1"),
|
||||
}, ResolverAddrs{"MockClient"}, nil
|
||||
}
|
||||
if hostname == "ipv6.localhost" {
|
||||
return []netip.Addr{
|
||||
netip.MustParseAddr("::1"),
|
||||
}, ResolverAddrs{"MockClient"}, nil
|
||||
}
|
||||
return []netip.Addr{netip.MustParseAddr("127.0.0.1")}, ResolverAddrs{"MockClient"}, nil
|
||||
}
|
||||
|
||||
// LookupCAA returns mock records for use in tests.
|
||||
func (mock *MockClient) LookupCAA(_ context.Context, domain string) ([]*dns.CAA, string, ResolverAddrs, error) {
|
||||
return nil, "", ResolverAddrs{"MockClient"}, nil
|
||||
}
|
||||
|
|
@ -1,159 +0,0 @@
|
|||
package bdns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
// Error wraps a DNS error with various relevant information
|
||||
type Error struct {
|
||||
recordType uint16
|
||||
hostname string
|
||||
// Exactly one of rCode or underlying should be set.
|
||||
underlying error
|
||||
rCode int
|
||||
|
||||
// Optional: If the resolver returned extended error information, it will be stored here.
|
||||
// https://www.rfc-editor.org/rfc/rfc8914
|
||||
extended *dns.EDNS0_EDE
|
||||
}
|
||||
|
||||
// extendedDNSError returns non-nil if the input message contained an OPT RR
|
||||
// with an EDE option. https://www.rfc-editor.org/rfc/rfc8914.
|
||||
func extendedDNSError(msg *dns.Msg) *dns.EDNS0_EDE {
|
||||
opt := msg.IsEdns0()
|
||||
if opt != nil {
|
||||
for _, opt := range opt.Option {
|
||||
ede, ok := opt.(*dns.EDNS0_EDE)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
return ede
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// wrapErr returns a non-nil error if err is non-nil or if resp.Rcode is not dns.RcodeSuccess.
|
||||
// The error includes appropriate details about the DNS query that failed.
|
||||
func wrapErr(queryType uint16, hostname string, resp *dns.Msg, err error) error {
|
||||
if err != nil {
|
||||
return Error{
|
||||
recordType: queryType,
|
||||
hostname: hostname,
|
||||
underlying: err,
|
||||
extended: nil,
|
||||
}
|
||||
}
|
||||
if resp.Rcode != dns.RcodeSuccess {
|
||||
return Error{
|
||||
recordType: queryType,
|
||||
hostname: hostname,
|
||||
rCode: resp.Rcode,
|
||||
underlying: nil,
|
||||
extended: extendedDNSError(resp),
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A copy of miekg/dns's mapping of error codes to strings. We tweak it slightly so all DNSSEC-related
|
||||
// errors say "DNSSEC" at the beginning.
|
||||
// https://pkg.go.dev/github.com/miekg/dns#ExtendedErrorCodeToString
|
||||
// Also note that not all of these codes can currently be emitted by Unbound. See Unbound's
|
||||
// announcement post for EDE: https://blog.nlnetlabs.nl/extended-dns-error-support-for-unbound/
|
||||
var extendedErrorCodeToString = map[uint16]string{
|
||||
dns.ExtendedErrorCodeOther: "Other",
|
||||
dns.ExtendedErrorCodeUnsupportedDNSKEYAlgorithm: "DNSSEC: Unsupported DNSKEY Algorithm",
|
||||
dns.ExtendedErrorCodeUnsupportedDSDigestType: "DNSSEC: Unsupported DS Digest Type",
|
||||
dns.ExtendedErrorCodeStaleAnswer: "Stale Answer",
|
||||
dns.ExtendedErrorCodeForgedAnswer: "Forged Answer",
|
||||
dns.ExtendedErrorCodeDNSSECIndeterminate: "DNSSEC: Indeterminate",
|
||||
dns.ExtendedErrorCodeDNSBogus: "DNSSEC: Bogus",
|
||||
dns.ExtendedErrorCodeSignatureExpired: "DNSSEC: Signature Expired",
|
||||
dns.ExtendedErrorCodeSignatureNotYetValid: "DNSSEC: Signature Not Yet Valid",
|
||||
dns.ExtendedErrorCodeDNSKEYMissing: "DNSSEC: DNSKEY Missing",
|
||||
dns.ExtendedErrorCodeRRSIGsMissing: "DNSSEC: RRSIGs Missing",
|
||||
dns.ExtendedErrorCodeNoZoneKeyBitSet: "DNSSEC: No Zone Key Bit Set",
|
||||
dns.ExtendedErrorCodeNSECMissing: "DNSSEC: NSEC Missing",
|
||||
dns.ExtendedErrorCodeCachedError: "Cached Error",
|
||||
dns.ExtendedErrorCodeNotReady: "Not Ready",
|
||||
dns.ExtendedErrorCodeBlocked: "Blocked",
|
||||
dns.ExtendedErrorCodeCensored: "Censored",
|
||||
dns.ExtendedErrorCodeFiltered: "Filtered",
|
||||
dns.ExtendedErrorCodeProhibited: "Prohibited",
|
||||
dns.ExtendedErrorCodeStaleNXDOMAINAnswer: "Stale NXDOMAIN Answer",
|
||||
dns.ExtendedErrorCodeNotAuthoritative: "Not Authoritative",
|
||||
dns.ExtendedErrorCodeNotSupported: "Not Supported",
|
||||
dns.ExtendedErrorCodeNoReachableAuthority: "No Reachable Authority",
|
||||
dns.ExtendedErrorCodeNetworkError: "Network Error between Resolver and Authority",
|
||||
dns.ExtendedErrorCodeInvalidData: "Invalid Data",
|
||||
}
|
||||
|
||||
func (d Error) Error() string {
|
||||
var detail, additional string
|
||||
if d.underlying != nil {
|
||||
var netErr *net.OpError
|
||||
var urlErr *url.Error
|
||||
if errors.As(d.underlying, &netErr) {
|
||||
if netErr.Timeout() {
|
||||
detail = detailDNSTimeout
|
||||
} else {
|
||||
detail = detailDNSNetFailure
|
||||
}
|
||||
// Note: we check d.underlying here even though `Timeout()` does this because the call to `netErr.Timeout()` above only
|
||||
// happens for `*net.OpError` underlying types!
|
||||
} else if errors.As(d.underlying, &urlErr) && urlErr.Timeout() {
|
||||
// For DOH queries, we can get back a `*url.Error` that wraps the unexported type
|
||||
// `http.httpError`. Unfortunately `http.httpError` doesn't wrap any errors (like
|
||||
// context.DeadlineExceeded), we can't check for that; instead we need to call Timeout().
|
||||
detail = detailDNSTimeout
|
||||
} else if errors.Is(d.underlying, context.DeadlineExceeded) {
|
||||
detail = detailDNSTimeout
|
||||
} else if errors.Is(d.underlying, context.Canceled) {
|
||||
detail = detailCanceled
|
||||
} else {
|
||||
detail = detailServerFailure
|
||||
}
|
||||
} else if d.rCode != dns.RcodeSuccess {
|
||||
detail = dns.RcodeToString[d.rCode]
|
||||
if explanation, ok := rcodeExplanations[d.rCode]; ok {
|
||||
additional = " - " + explanation
|
||||
}
|
||||
} else {
|
||||
detail = detailServerFailure
|
||||
}
|
||||
|
||||
if d.extended == nil {
|
||||
return fmt.Sprintf("DNS problem: %s looking up %s for %s%s", detail,
|
||||
dns.TypeToString[d.recordType], d.hostname, additional)
|
||||
}
|
||||
|
||||
summary := extendedErrorCodeToString[d.extended.InfoCode]
|
||||
if summary == "" {
|
||||
summary = fmt.Sprintf("Unknown Extended DNS Error code %d", d.extended.InfoCode)
|
||||
}
|
||||
result := fmt.Sprintf("DNS problem: looking up %s for %s: %s",
|
||||
dns.TypeToString[d.recordType], d.hostname, summary)
|
||||
if d.extended.ExtraText != "" {
|
||||
result = result + ": " + d.extended.ExtraText
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const detailDNSTimeout = "query timed out"
|
||||
const detailCanceled = "query timed out (and was canceled)"
|
||||
const detailDNSNetFailure = "networking error"
|
||||
const detailServerFailure = "server failure at resolver"
|
||||
|
||||
// rcodeExplanations provide additional friendly explanatory text to be included in DNS
|
||||
// error messages, for select inscrutable RCODEs.
|
||||
var rcodeExplanations = map[int]string{
|
||||
dns.RcodeNameError: "check that a DNS record exists for this domain",
|
||||
dns.RcodeServerFailure: "the domain's nameservers may be malfunctioning",
|
||||
}
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
package bdns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
"github.com/letsencrypt/boulder/test"
|
||||
"github.com/miekg/dns"
|
||||
)
|
||||
|
||||
func TestError(t *testing.T) {
|
||||
testCases := []struct {
|
||||
err error
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
&Error{dns.TypeA, "hostname", makeTimeoutError(), -1, nil},
|
||||
"DNS problem: query timed out looking up A for hostname",
|
||||
}, {
|
||||
&Error{dns.TypeMX, "hostname", &net.OpError{Err: errors.New("some net error")}, -1, nil},
|
||||
"DNS problem: networking error looking up MX for hostname",
|
||||
}, {
|
||||
&Error{dns.TypeTXT, "hostname", nil, dns.RcodeNameError, nil},
|
||||
"DNS problem: NXDOMAIN looking up TXT for hostname - check that a DNS record exists for this domain",
|
||||
}, {
|
||||
&Error{dns.TypeTXT, "hostname", context.DeadlineExceeded, -1, nil},
|
||||
"DNS problem: query timed out looking up TXT for hostname",
|
||||
}, {
|
||||
&Error{dns.TypeTXT, "hostname", context.Canceled, -1, nil},
|
||||
"DNS problem: query timed out (and was canceled) looking up TXT for hostname",
|
||||
}, {
|
||||
&Error{dns.TypeCAA, "hostname", nil, dns.RcodeServerFailure, nil},
|
||||
"DNS problem: SERVFAIL looking up CAA for hostname - the domain's nameservers may be malfunctioning",
|
||||
}, {
|
||||
&Error{dns.TypeA, "hostname", nil, dns.RcodeServerFailure, &dns.EDNS0_EDE{InfoCode: 1, ExtraText: "oh no"}},
|
||||
"DNS problem: looking up A for hostname: DNSSEC: Unsupported DNSKEY Algorithm: oh no",
|
||||
}, {
|
||||
&Error{dns.TypeA, "hostname", nil, dns.RcodeServerFailure, &dns.EDNS0_EDE{InfoCode: 6, ExtraText: ""}},
|
||||
"DNS problem: looking up A for hostname: DNSSEC: Bogus",
|
||||
}, {
|
||||
&Error{dns.TypeA, "hostname", nil, dns.RcodeServerFailure, &dns.EDNS0_EDE{InfoCode: 1337, ExtraText: "mysterious"}},
|
||||
"DNS problem: looking up A for hostname: Unknown Extended DNS Error code 1337: mysterious",
|
||||
}, {
|
||||
&Error{dns.TypeCAA, "hostname", nil, dns.RcodeServerFailure, nil},
|
||||
"DNS problem: SERVFAIL looking up CAA for hostname - the domain's nameservers may be malfunctioning",
|
||||
}, {
|
||||
&Error{dns.TypeCAA, "hostname", nil, dns.RcodeServerFailure, nil},
|
||||
"DNS problem: SERVFAIL looking up CAA for hostname - the domain's nameservers may be malfunctioning",
|
||||
}, {
|
||||
&Error{dns.TypeA, "hostname", nil, dns.RcodeFormatError, nil},
|
||||
"DNS problem: FORMERR looking up A for hostname",
|
||||
}, {
|
||||
&Error{dns.TypeA, "hostname", &url.Error{Op: "GET", URL: "https://example.com/", Err: dohTimeoutError{}}, -1, nil},
|
||||
"DNS problem: query timed out looking up A for hostname",
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
if tc.err.Error() != tc.expected {
|
||||
t.Errorf("got %q, expected %q", tc.err.Error(), tc.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type dohTimeoutError struct{}
|
||||
|
||||
func (dohTimeoutError) Error() string {
|
||||
return "doh no"
|
||||
}
|
||||
|
||||
func (dohTimeoutError) Timeout() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func TestWrapErr(t *testing.T) {
|
||||
err := wrapErr(dns.TypeA, "hostname", &dns.Msg{
|
||||
MsgHdr: dns.MsgHdr{Rcode: dns.RcodeSuccess},
|
||||
}, nil)
|
||||
test.AssertNotError(t, err, "expected success")
|
||||
|
||||
err = wrapErr(dns.TypeA, "hostname", &dns.Msg{
|
||||
MsgHdr: dns.MsgHdr{Rcode: dns.RcodeRefused},
|
||||
}, nil)
|
||||
test.AssertError(t, err, "expected error")
|
||||
|
||||
err = wrapErr(dns.TypeA, "hostname", &dns.Msg{
|
||||
MsgHdr: dns.MsgHdr{Rcode: dns.RcodeSuccess},
|
||||
}, errors.New("oh no"))
|
||||
test.AssertError(t, err, "expected error")
|
||||
}
|
||||
|
|
@ -1,325 +0,0 @@
|
|||
package bdns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand/v2"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"github.com/letsencrypt/boulder/cmd"
|
||||
)
|
||||
|
||||
// ServerProvider represents a type which can provide a list of addresses for
|
||||
// the bdns to use as DNS resolvers. Different implementations may provide
|
||||
// different strategies for providing addresses, and may provide different kinds
|
||||
// of addresses (e.g. host:port combos vs IP addresses).
|
||||
type ServerProvider interface {
|
||||
Addrs() ([]string, error)
|
||||
Stop()
|
||||
}
|
||||
|
||||
// staticProvider stores a list of host:port combos, and provides that whole
|
||||
// list in randomized order when asked for addresses. This replicates the old
|
||||
// behavior of the bdns.impl's servers field.
|
||||
type staticProvider struct {
|
||||
servers []string
|
||||
}
|
||||
|
||||
var _ ServerProvider = &staticProvider{}
|
||||
|
||||
// validateServerAddress ensures that a given server address is formatted in
|
||||
// such a way that it can be dialed. The provided server address must include a
|
||||
// host/IP and port separated by colon. Additionally, if the host is a literal
|
||||
// IPv6 address, it must be enclosed in square brackets.
|
||||
// (https://golang.org/src/net/dial.go?s=9833:9881#L281)
|
||||
func validateServerAddress(address string) error {
|
||||
// Ensure the host and port portions of `address` can be split.
|
||||
host, port, err := net.SplitHostPort(address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure `address` contains both a `host` and `port` portion.
|
||||
if host == "" || port == "" {
|
||||
return errors.New("port cannot be missing")
|
||||
}
|
||||
|
||||
// Ensure the `port` portion of `address` is a valid port.
|
||||
portNum, err := strconv.Atoi(port)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing port number: %s", err)
|
||||
}
|
||||
if portNum <= 0 || portNum > 65535 {
|
||||
return errors.New("port must be an integer between 0 - 65535")
|
||||
}
|
||||
|
||||
// Ensure the `host` portion of `address` is a valid FQDN or IP address.
|
||||
_, err = netip.ParseAddr(host)
|
||||
FQDN := dns.IsFqdn(dns.Fqdn(host))
|
||||
if err != nil && !FQDN {
|
||||
return errors.New("host is not an FQDN or IP address")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewStaticProvider(servers []string) (*staticProvider, error) {
|
||||
var serverAddrs []string
|
||||
for _, server := range servers {
|
||||
err := validateServerAddress(server)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("server address %q invalid: %s", server, err)
|
||||
}
|
||||
serverAddrs = append(serverAddrs, server)
|
||||
}
|
||||
return &staticProvider{servers: serverAddrs}, nil
|
||||
}
|
||||
|
||||
func (sp *staticProvider) Addrs() ([]string, error) {
|
||||
if len(sp.servers) == 0 {
|
||||
return nil, fmt.Errorf("no servers configured")
|
||||
}
|
||||
r := make([]string, len(sp.servers))
|
||||
perm := rand.Perm(len(sp.servers))
|
||||
for i, v := range perm {
|
||||
r[i] = sp.servers[v]
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
func (sp *staticProvider) Stop() {}
|
||||
|
||||
// dynamicProvider uses DNS to look up the set of IP addresses which correspond
|
||||
// to its single host. It returns this list in random order when asked for
|
||||
// addresses, and refreshes it regularly using a goroutine started by its
|
||||
// constructor.
|
||||
type dynamicProvider struct {
|
||||
// dnsAuthority is the single <hostname|IPv4|[IPv6]>:<port> of the DNS
|
||||
// server to be used for resolution of DNS backends. If the address contains
|
||||
// a hostname it will be resolved via the system DNS. If the port is left
|
||||
// unspecified it will default to '53'. If this field is left unspecified
|
||||
// the system DNS will be used for resolution of DNS backends.
|
||||
dnsAuthority string
|
||||
// service is the service name to look up SRV records for within the domain.
|
||||
// If this field is left unspecified 'dns' will be used as the service name.
|
||||
service string
|
||||
// proto is the IP protocol (tcp or udp) to look up SRV records for.
|
||||
proto string
|
||||
// domain is the name to look up SRV records within.
|
||||
domain string
|
||||
// A map of IP addresses (results of A record lookups for SRV Targets) to
|
||||
// ports (Port fields in SRV records) associated with those addresses.
|
||||
addrs map[string][]uint16
|
||||
// Other internal bookkeeping state.
|
||||
cancel chan interface{}
|
||||
mu sync.RWMutex
|
||||
refresh time.Duration
|
||||
updateCounter *prometheus.CounterVec
|
||||
}
|
||||
|
||||
// ParseTarget takes the user input target string and default port, returns
|
||||
// formatted host and port info. If target doesn't specify a port, set the port
|
||||
// to be the defaultPort. If target is in IPv6 format and host-name is enclosed
|
||||
// in square brackets, brackets are stripped when setting the host.
|
||||
//
|
||||
// Examples:
|
||||
// - target: "www.google.com" defaultPort: "443" returns host: "www.google.com", port: "443"
|
||||
// - target: "ipv4-host:80" defaultPort: "443" returns host: "ipv4-host", port: "80"
|
||||
// - target: "[ipv6-host]" defaultPort: "443" returns host: "ipv6-host", port: "443"
|
||||
// - target: ":80" defaultPort: "443" returns host: "localhost", port: "80"
|
||||
//
|
||||
// This function is copied from:
|
||||
// https://github.com/grpc/grpc-go/blob/master/internal/resolver/dns/dns_resolver.go
|
||||
// It has been minimally modified to fit our code style.
|
||||
func ParseTarget(target, defaultPort string) (host, port string, err error) {
|
||||
if target == "" {
|
||||
return "", "", errors.New("missing address")
|
||||
}
|
||||
ip := net.ParseIP(target)
|
||||
if ip != nil {
|
||||
// Target is an IPv4 or IPv6(without brackets) address.
|
||||
return target, defaultPort, nil
|
||||
}
|
||||
host, port, err = net.SplitHostPort(target)
|
||||
if err == nil {
|
||||
if port == "" {
|
||||
// If the port field is empty (target ends with colon), e.g.
|
||||
// "[::1]:", this is an error.
|
||||
return "", "", errors.New("missing port after port-separator colon")
|
||||
}
|
||||
// target has port, i.e ipv4-host:port, [ipv6-host]:port, host-name:port
|
||||
if host == "" {
|
||||
// Keep consistent with net.Dial(): If the host is empty, as in
|
||||
// ":80", the local system is assumed.
|
||||
host = "localhost"
|
||||
}
|
||||
return host, port, nil
|
||||
}
|
||||
host, port, err = net.SplitHostPort(target + ":" + defaultPort)
|
||||
if err == nil {
|
||||
// Target doesn't have port.
|
||||
return host, port, nil
|
||||
}
|
||||
return "", "", fmt.Errorf("invalid target address %v, error info: %v", target, err)
|
||||
}
|
||||
|
||||
var _ ServerProvider = &dynamicProvider{}
|
||||
|
||||
// StartDynamicProvider constructs a new dynamicProvider and starts its
|
||||
// auto-update goroutine. The auto-update process queries DNS for SRV records
|
||||
// at refresh intervals and uses the resulting IP/port combos to populate the
|
||||
// list returned by Addrs. The update process ignores the Priority and Weight
|
||||
// attributes of the SRV records.
|
||||
//
|
||||
// `proto` is the IP protocol (tcp or udp) to look up SRV records for.
|
||||
func StartDynamicProvider(c *cmd.DNSProvider, refresh time.Duration, proto string) (*dynamicProvider, error) {
|
||||
if c.SRVLookup.Domain == "" {
|
||||
return nil, fmt.Errorf("'domain' cannot be empty")
|
||||
}
|
||||
|
||||
service := c.SRVLookup.Service
|
||||
if service == "" {
|
||||
// Default to "dns" if no service is specified. This is the default
|
||||
// service name for DNS servers.
|
||||
service = "dns"
|
||||
}
|
||||
|
||||
host, port, err := ParseTarget(c.DNSAuthority, "53")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dnsAuthority := net.JoinHostPort(host, port)
|
||||
err = validateServerAddress(dnsAuthority)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dp := dynamicProvider{
|
||||
dnsAuthority: dnsAuthority,
|
||||
service: service,
|
||||
proto: proto,
|
||||
domain: c.SRVLookup.Domain,
|
||||
addrs: make(map[string][]uint16),
|
||||
cancel: make(chan interface{}),
|
||||
refresh: refresh,
|
||||
updateCounter: prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "dns_update",
|
||||
Help: "Counter of attempts to update a dynamic provider",
|
||||
},
|
||||
[]string{"success"},
|
||||
),
|
||||
}
|
||||
|
||||
// Update once immediately, so we can know whether that was successful, then
|
||||
// kick off the long-running update goroutine.
|
||||
err = dp.update()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to start dynamic provider: %w", err)
|
||||
}
|
||||
go dp.run()
|
||||
|
||||
return &dp, nil
|
||||
}
|
||||
|
||||
// run loops forever, calling dp.update() every dp.refresh interval. Does not
|
||||
// halt until the dp.cancel channel is closed, so should be run in a goroutine.
|
||||
func (dp *dynamicProvider) run() {
|
||||
t := time.NewTicker(dp.refresh)
|
||||
for {
|
||||
select {
|
||||
case <-t.C:
|
||||
err := dp.update()
|
||||
if err != nil {
|
||||
dp.updateCounter.With(prometheus.Labels{
|
||||
"success": "false",
|
||||
}).Inc()
|
||||
continue
|
||||
}
|
||||
dp.updateCounter.With(prometheus.Labels{
|
||||
"success": "true",
|
||||
}).Inc()
|
||||
case <-dp.cancel:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update performs the SRV and A record queries necessary to map the given DNS
|
||||
// domain name to a set of cacheable IP addresses and ports, and stores the
|
||||
// results in dp.addrs.
|
||||
func (dp *dynamicProvider) update() error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), dp.refresh/2)
|
||||
defer cancel()
|
||||
|
||||
resolver := &net.Resolver{
|
||||
PreferGo: true,
|
||||
Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
|
||||
d := &net.Dialer{}
|
||||
return d.DialContext(ctx, network, dp.dnsAuthority)
|
||||
},
|
||||
}
|
||||
|
||||
// RFC 2782 formatted SRV record being queried e.g. "_service._proto.name."
|
||||
record := fmt.Sprintf("_%s._%s.%s.", dp.service, dp.proto, dp.domain)
|
||||
|
||||
_, srvs, err := resolver.LookupSRV(ctx, dp.service, dp.proto, dp.domain)
|
||||
if err != nil {
|
||||
return fmt.Errorf("during SRV lookup of %q: %w", record, err)
|
||||
}
|
||||
if len(srvs) == 0 {
|
||||
return fmt.Errorf("SRV lookup of %q returned 0 results", record)
|
||||
}
|
||||
|
||||
addrPorts := make(map[string][]uint16)
|
||||
for _, srv := range srvs {
|
||||
addrs, err := resolver.LookupHost(ctx, srv.Target)
|
||||
if err != nil {
|
||||
return fmt.Errorf("during A/AAAA lookup of target %q from SRV record %q: %w", srv.Target, record, err)
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
joinedHostPort := net.JoinHostPort(addr, fmt.Sprint(srv.Port))
|
||||
err := validateServerAddress(joinedHostPort)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid addr %q from SRV record %q: %w", joinedHostPort, record, err)
|
||||
}
|
||||
addrPorts[addr] = append(addrPorts[addr], srv.Port)
|
||||
}
|
||||
}
|
||||
|
||||
dp.mu.Lock()
|
||||
dp.addrs = addrPorts
|
||||
dp.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Addrs returns a shuffled list of IP/port pairs, with the guarantee that no
|
||||
// two IP/port pairs will share the same IP.
|
||||
func (dp *dynamicProvider) Addrs() ([]string, error) {
|
||||
var r []string
|
||||
dp.mu.RLock()
|
||||
for ip, ports := range dp.addrs {
|
||||
port := fmt.Sprint(ports[rand.IntN(len(ports))])
|
||||
addr := net.JoinHostPort(ip, port)
|
||||
r = append(r, addr)
|
||||
}
|
||||
dp.mu.RUnlock()
|
||||
rand.Shuffle(len(r), func(i, j int) {
|
||||
r[i], r[j] = r[j], r[i]
|
||||
})
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// Stop tells the background update goroutine to cease. It does not wait for
|
||||
// confirmation that it has done so.
|
||||
func (dp *dynamicProvider) Stop() {
|
||||
close(dp.cancel)
|
||||
}
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
package bdns
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/letsencrypt/boulder/test"
|
||||
)
|
||||
|
||||
func Test_validateServerAddress(t *testing.T) {
|
||||
type args struct {
|
||||
server string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantErr bool
|
||||
}{
|
||||
// ipv4 cases
|
||||
{"ipv4 with port", args{"1.1.1.1:53"}, false},
|
||||
// sad path
|
||||
{"ipv4 without port", args{"1.1.1.1"}, true},
|
||||
{"ipv4 port num missing", args{"1.1.1.1:"}, true},
|
||||
{"ipv4 string for port", args{"1.1.1.1:foo"}, true},
|
||||
{"ipv4 port out of range high", args{"1.1.1.1:65536"}, true},
|
||||
{"ipv4 port out of range low", args{"1.1.1.1:0"}, true},
|
||||
|
||||
// ipv6 cases
|
||||
{"ipv6 with port", args{"[2606:4700:4700::1111]:53"}, false},
|
||||
// sad path
|
||||
{"ipv6 sans brackets", args{"2606:4700:4700::1111:53"}, true},
|
||||
{"ipv6 without port", args{"[2606:4700:4700::1111]"}, true},
|
||||
{"ipv6 port num missing", args{"[2606:4700:4700::1111]:"}, true},
|
||||
{"ipv6 string for port", args{"[2606:4700:4700::1111]:foo"}, true},
|
||||
{"ipv6 port out of range high", args{"[2606:4700:4700::1111]:65536"}, true},
|
||||
{"ipv6 port out of range low", args{"[2606:4700:4700::1111]:0"}, true},
|
||||
|
||||
// hostname cases
|
||||
{"hostname with port", args{"foo:53"}, false},
|
||||
// sad path
|
||||
{"hostname without port", args{"foo"}, true},
|
||||
{"hostname port num missing", args{"foo:"}, true},
|
||||
{"hostname string for port", args{"foo:bar"}, true},
|
||||
{"hostname port out of range high", args{"foo:65536"}, true},
|
||||
{"hostname port out of range low", args{"foo:0"}, true},
|
||||
|
||||
// fqdn cases
|
||||
{"fqdn with port", args{"bar.foo.baz:53"}, false},
|
||||
// sad path
|
||||
{"fqdn without port", args{"bar.foo.baz"}, true},
|
||||
{"fqdn port num missing", args{"bar.foo.baz:"}, true},
|
||||
{"fqdn string for port", args{"bar.foo.baz:bar"}, true},
|
||||
{"fqdn port out of range high", args{"bar.foo.baz:65536"}, true},
|
||||
{"fqdn port out of range low", args{"bar.foo.baz:0"}, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := validateServerAddress(tt.args.server)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("formatServer() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_resolveDNSAuthority(t *testing.T) {
|
||||
type want struct {
|
||||
host string
|
||||
port string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
target string
|
||||
want want
|
||||
wantErr bool
|
||||
}{
|
||||
{"IP4 with port", "10.10.10.10:53", want{"10.10.10.10", "53"}, false},
|
||||
{"IP4 without port", "10.10.10.10", want{"10.10.10.10", "53"}, false},
|
||||
{"IP6 with port and brackets", "[2606:4700:4700::1111]:53", want{"2606:4700:4700::1111", "53"}, false},
|
||||
{"IP6 without port", "2606:4700:4700::1111", want{"2606:4700:4700::1111", "53"}, false},
|
||||
{"IP6 with brackets without port", "[2606:4700:4700::1111]", want{"2606:4700:4700::1111", "53"}, false},
|
||||
{"hostname with port", "localhost:53", want{"localhost", "53"}, false},
|
||||
{"hostname without port", "localhost", want{"localhost", "53"}, false},
|
||||
{"only port", ":53", want{"localhost", "53"}, false},
|
||||
{"hostname with no port after colon", "localhost:", want{"", ""}, true},
|
||||
{"IP4 with no port after colon", "10.10.10.10:", want{"", ""}, true},
|
||||
{"IP6 with no port after colon", "[2606:4700:4700::1111]:", want{"", ""}, true},
|
||||
{"no hostname or port", "", want{"", ""}, true},
|
||||
{"invalid addr", "foo:bar:baz", want{"", ""}, true},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotHost, gotPort, gotErr := ParseTarget(tt.target, "53")
|
||||
test.AssertEquals(t, gotHost, tt.want.host)
|
||||
test.AssertEquals(t, gotPort, tt.want.port)
|
||||
if tt.wantErr {
|
||||
test.AssertError(t, gotErr, "expected error")
|
||||
} else {
|
||||
test.AssertNotError(t, gotErr, "unexpected error")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
696
third-party/github.com/letsencrypt/boulder/ca/ca.go
vendored
696
third-party/github.com/letsencrypt/boulder/ca/ca.go
vendored
|
|
@ -1,696 +0,0 @@
|
|||
package ca
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
mrand "math/rand/v2"
|
||||
"time"
|
||||
|
||||
ct "github.com/google/certificate-transparency-go"
|
||||
cttls "github.com/google/certificate-transparency-go/tls"
|
||||
"github.com/jmhodges/clock"
|
||||
"github.com/miekg/pkcs11"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
|
||||
"golang.org/x/crypto/ocsp"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
capb "github.com/letsencrypt/boulder/ca/proto"
|
||||
"github.com/letsencrypt/boulder/core"
|
||||
csrlib "github.com/letsencrypt/boulder/csr"
|
||||
berrors "github.com/letsencrypt/boulder/errors"
|
||||
"github.com/letsencrypt/boulder/goodkey"
|
||||
"github.com/letsencrypt/boulder/identifier"
|
||||
"github.com/letsencrypt/boulder/issuance"
|
||||
"github.com/letsencrypt/boulder/linter"
|
||||
blog "github.com/letsencrypt/boulder/log"
|
||||
rapb "github.com/letsencrypt/boulder/ra/proto"
|
||||
sapb "github.com/letsencrypt/boulder/sa/proto"
|
||||
)
|
||||
|
||||
type certificateType string
|
||||
|
||||
const (
|
||||
precertType = certificateType("precertificate")
|
||||
certType = certificateType("certificate")
|
||||
)
|
||||
|
||||
// issuanceEvent is logged before and after issuance of precertificates and certificates.
|
||||
// The `omitempty` fields are not always present.
|
||||
// CSR, Precertificate, and Certificate are hex-encoded DER bytes to make it easier to
|
||||
// ad-hoc search for sequences or OIDs in logs. Other data, like public key within CSR,
|
||||
// is logged as base64 because it doesn't have interesting DER structure.
|
||||
type issuanceEvent struct {
|
||||
CSR string `json:",omitempty"`
|
||||
IssuanceRequest *issuance.IssuanceRequest
|
||||
Issuer string
|
||||
OrderID int64
|
||||
Profile string
|
||||
Requester int64
|
||||
Result struct {
|
||||
Precertificate string `json:",omitempty"`
|
||||
Certificate string `json:",omitempty"`
|
||||
}
|
||||
}
|
||||
|
||||
// Two maps of keys to Issuers. Lookup by PublicKeyAlgorithm is useful for
|
||||
// determining the set of issuers which can sign a given (pre)cert, based on its
|
||||
// PublicKeyAlgorithm. Lookup by NameID is useful for looking up a specific
|
||||
// issuer based on the issuer of a given (pre)certificate.
|
||||
type issuerMaps struct {
|
||||
byAlg map[x509.PublicKeyAlgorithm][]*issuance.Issuer
|
||||
byNameID map[issuance.NameID]*issuance.Issuer
|
||||
}
|
||||
|
||||
type certProfileWithID struct {
|
||||
// name is a human readable name used to refer to the certificate profile.
|
||||
name string
|
||||
profile *issuance.Profile
|
||||
}
|
||||
|
||||
// caMetrics holds various metrics which are shared between caImpl, ocspImpl,
|
||||
// and crlImpl.
|
||||
type caMetrics struct {
|
||||
signatureCount *prometheus.CounterVec
|
||||
signErrorCount *prometheus.CounterVec
|
||||
lintErrorCount prometheus.Counter
|
||||
certificates *prometheus.CounterVec
|
||||
}
|
||||
|
||||
func NewCAMetrics(stats prometheus.Registerer) *caMetrics {
|
||||
signatureCount := prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "signatures",
|
||||
Help: "Number of signatures",
|
||||
},
|
||||
[]string{"purpose", "issuer"})
|
||||
stats.MustRegister(signatureCount)
|
||||
|
||||
signErrorCount := prometheus.NewCounterVec(prometheus.CounterOpts{
|
||||
Name: "signature_errors",
|
||||
Help: "A counter of signature errors labelled by error type",
|
||||
}, []string{"type"})
|
||||
stats.MustRegister(signErrorCount)
|
||||
|
||||
lintErrorCount := prometheus.NewCounter(
|
||||
prometheus.CounterOpts{
|
||||
Name: "lint_errors",
|
||||
Help: "Number of issuances that were halted by linting errors",
|
||||
})
|
||||
stats.MustRegister(lintErrorCount)
|
||||
|
||||
certificates := prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: "certificates",
|
||||
Help: "Number of certificates issued",
|
||||
},
|
||||
[]string{"profile"})
|
||||
stats.MustRegister(certificates)
|
||||
|
||||
return &caMetrics{signatureCount, signErrorCount, lintErrorCount, certificates}
|
||||
}
|
||||
|
||||
func (m *caMetrics) noteSignError(err error) {
|
||||
var pkcs11Error pkcs11.Error
|
||||
if errors.As(err, &pkcs11Error) {
|
||||
m.signErrorCount.WithLabelValues("HSM").Inc()
|
||||
}
|
||||
}
|
||||
|
||||
// certificateAuthorityImpl represents a CA that signs certificates.
|
||||
// It can sign OCSP responses as well, but only via delegation to an ocspImpl.
|
||||
type certificateAuthorityImpl struct {
|
||||
capb.UnsafeCertificateAuthorityServer
|
||||
sa sapb.StorageAuthorityCertificateClient
|
||||
sctClient rapb.SCTProviderClient
|
||||
pa core.PolicyAuthority
|
||||
issuers issuerMaps
|
||||
certProfiles map[string]*certProfileWithID
|
||||
|
||||
// The prefix is prepended to the serial number.
|
||||
prefix byte
|
||||
maxNames int
|
||||
keyPolicy goodkey.KeyPolicy
|
||||
clk clock.Clock
|
||||
log blog.Logger
|
||||
metrics *caMetrics
|
||||
tracer trace.Tracer
|
||||
}
|
||||
|
||||
var _ capb.CertificateAuthorityServer = (*certificateAuthorityImpl)(nil)
|
||||
|
||||
// makeIssuerMaps processes a list of issuers into a set of maps for easy
|
||||
// lookup either by key algorithm (useful for picking an issuer for a precert)
|
||||
// or by unique ID (useful for final certs, OCSP, and CRLs). If two issuers with
|
||||
// the same unique ID are encountered, an error is returned.
|
||||
func makeIssuerMaps(issuers []*issuance.Issuer) (issuerMaps, error) {
|
||||
issuersByAlg := make(map[x509.PublicKeyAlgorithm][]*issuance.Issuer, 2)
|
||||
issuersByNameID := make(map[issuance.NameID]*issuance.Issuer, len(issuers))
|
||||
for _, issuer := range issuers {
|
||||
if _, found := issuersByNameID[issuer.NameID()]; found {
|
||||
return issuerMaps{}, fmt.Errorf("two issuers with same NameID %d (%s) configured", issuer.NameID(), issuer.Name())
|
||||
}
|
||||
issuersByNameID[issuer.NameID()] = issuer
|
||||
if issuer.IsActive() {
|
||||
issuersByAlg[issuer.KeyType()] = append(issuersByAlg[issuer.KeyType()], issuer)
|
||||
}
|
||||
}
|
||||
if i, ok := issuersByAlg[x509.ECDSA]; !ok || len(i) == 0 {
|
||||
return issuerMaps{}, errors.New("no ECDSA issuers configured")
|
||||
}
|
||||
if i, ok := issuersByAlg[x509.RSA]; !ok || len(i) == 0 {
|
||||
return issuerMaps{}, errors.New("no RSA issuers configured")
|
||||
}
|
||||
return issuerMaps{issuersByAlg, issuersByNameID}, nil
|
||||
}
|
||||
|
||||
// makeCertificateProfilesMap processes a set of named certificate issuance
|
||||
// profile configs into a map from name to profile.
|
||||
func makeCertificateProfilesMap(profiles map[string]*issuance.ProfileConfig) (map[string]*certProfileWithID, error) {
|
||||
if len(profiles) <= 0 {
|
||||
return nil, fmt.Errorf("must pass at least one certificate profile")
|
||||
}
|
||||
|
||||
profilesByName := make(map[string]*certProfileWithID, len(profiles))
|
||||
|
||||
for name, profileConfig := range profiles {
|
||||
profile, err := issuance.NewProfile(profileConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
profilesByName[name] = &certProfileWithID{
|
||||
name: name,
|
||||
profile: profile,
|
||||
}
|
||||
}
|
||||
|
||||
return profilesByName, nil
|
||||
}
|
||||
|
||||
// NewCertificateAuthorityImpl creates a CA instance that can sign certificates
|
||||
// from any number of issuance.Issuers according to their profiles, and can sign
|
||||
// OCSP (via delegation to an ocspImpl and its issuers).
|
||||
func NewCertificateAuthorityImpl(
|
||||
sa sapb.StorageAuthorityCertificateClient,
|
||||
sctService rapb.SCTProviderClient,
|
||||
pa core.PolicyAuthority,
|
||||
boulderIssuers []*issuance.Issuer,
|
||||
certificateProfiles map[string]*issuance.ProfileConfig,
|
||||
serialPrefix byte,
|
||||
maxNames int,
|
||||
keyPolicy goodkey.KeyPolicy,
|
||||
logger blog.Logger,
|
||||
metrics *caMetrics,
|
||||
clk clock.Clock,
|
||||
) (*certificateAuthorityImpl, error) {
|
||||
var ca *certificateAuthorityImpl
|
||||
var err error
|
||||
|
||||
if serialPrefix < 0x01 || serialPrefix > 0x7f {
|
||||
err = errors.New("serial prefix must be between 0x01 (1) and 0x7f (127)")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(boulderIssuers) == 0 {
|
||||
return nil, errors.New("must have at least one issuer")
|
||||
}
|
||||
|
||||
certProfiles, err := makeCertificateProfilesMap(certificateProfiles)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
issuers, err := makeIssuerMaps(boulderIssuers)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ca = &certificateAuthorityImpl{
|
||||
sa: sa,
|
||||
sctClient: sctService,
|
||||
pa: pa,
|
||||
issuers: issuers,
|
||||
certProfiles: certProfiles,
|
||||
prefix: serialPrefix,
|
||||
maxNames: maxNames,
|
||||
keyPolicy: keyPolicy,
|
||||
log: logger,
|
||||
metrics: metrics,
|
||||
tracer: otel.GetTracerProvider().Tracer("github.com/letsencrypt/boulder/ca"),
|
||||
clk: clk,
|
||||
}
|
||||
|
||||
return ca, nil
|
||||
}
|
||||
|
||||
var ocspStatusToCode = map[string]int{
|
||||
"good": ocsp.Good,
|
||||
"revoked": ocsp.Revoked,
|
||||
"unknown": ocsp.Unknown,
|
||||
}
|
||||
|
||||
// issuePrecertificate is the first step in the [issuance cycle]. It allocates and stores a serial number,
|
||||
// selects a certificate profile, generates and stores a linting certificate, sets the serial's status to
|
||||
// "wait", signs and stores a precertificate, updates the serial's status to "good", then returns the
|
||||
// precertificate.
|
||||
//
|
||||
// Subsequent final issuance based on this precertificate must happen at most once, and must use the same
|
||||
// certificate profile.
|
||||
//
|
||||
// Returns precertificate DER.
|
||||
//
|
||||
// [issuance cycle]: https://github.com/letsencrypt/boulder/blob/main/docs/ISSUANCE-CYCLE.md
|
||||
func (ca *certificateAuthorityImpl) issuePrecertificate(ctx context.Context, certProfile *certProfileWithID, issueReq *capb.IssueCertificateRequest) ([]byte, error) {
|
||||
serialBigInt, err := ca.generateSerialNumber()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
notBefore, notAfter := certProfile.profile.GenerateValidity(ca.clk.Now())
|
||||
|
||||
serialHex := core.SerialToString(serialBigInt)
|
||||
regID := issueReq.RegistrationID
|
||||
_, err = ca.sa.AddSerial(ctx, &sapb.AddSerialRequest{
|
||||
Serial: serialHex,
|
||||
RegID: regID,
|
||||
Created: timestamppb.New(ca.clk.Now()),
|
||||
Expires: timestamppb.New(notAfter),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
precertDER, _, err := ca.issuePrecertificateInner(ctx, issueReq, certProfile, serialBigInt, notBefore, notAfter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = ca.sa.SetCertificateStatusReady(ctx, &sapb.Serial{Serial: serialHex})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return precertDER, nil
|
||||
}
|
||||
|
||||
func (ca *certificateAuthorityImpl) IssueCertificate(ctx context.Context, issueReq *capb.IssueCertificateRequest) (*capb.IssueCertificateResponse, error) {
|
||||
if core.IsAnyNilOrZero(issueReq, issueReq.Csr, issueReq.RegistrationID, issueReq.OrderID) {
|
||||
return nil, berrors.InternalServerError("Incomplete issue certificate request")
|
||||
}
|
||||
|
||||
if ca.sctClient == nil {
|
||||
return nil, errors.New("IssueCertificate called with a nil SCT service")
|
||||
}
|
||||
|
||||
// All issuance requests must come with a profile name, and the RA handles selecting the default.
|
||||
certProfile, ok := ca.certProfiles[issueReq.CertProfileName]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("the CA is incapable of using a profile named %s", issueReq.CertProfileName)
|
||||
}
|
||||
precertDER, err := ca.issuePrecertificate(ctx, certProfile, issueReq)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
scts, err := ca.sctClient.GetSCTs(ctx, &rapb.SCTRequest{PrecertDER: precertDER})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
certDER, err := ca.issueCertificateForPrecertificate(ctx, certProfile, precertDER, scts.SctDER, issueReq.RegistrationID, issueReq.OrderID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &capb.IssueCertificateResponse{DER: certDER}, nil
|
||||
}
|
||||
|
||||
// issueCertificateForPrecertificate is final step in the [issuance cycle].
|
||||
//
|
||||
// Given a precertificate and a set of SCTs for that precertificate, it generates
|
||||
// a linting final certificate, then signs a final certificate using a real issuer.
|
||||
// The poison extension is removed from the precertificate and a
|
||||
// SCT list extension is inserted in its place. Except for this and the
|
||||
// signature the final certificate exactly matches the precertificate.
|
||||
//
|
||||
// It's critical not to sign two different final certificates for the same
|
||||
// precertificate. This can happen, for instance, if the caller provides a
|
||||
// different set of SCTs on subsequent calls to issueCertificateForPrecertificate.
|
||||
// We rely on the RA not to call issueCertificateForPrecertificate twice for the
|
||||
// same serial. This is accomplished by the fact that
|
||||
// issueCertificateForPrecertificate is only ever called once per call to `IssueCertificate`.
|
||||
// If there is any error, the whole certificate issuance attempt fails and any subsequent
|
||||
// issuance will use a different serial number.
|
||||
//
|
||||
// We also check that the provided serial number does not already exist as a
|
||||
// final certificate, but this is just a belt-and-suspenders measure, since
|
||||
// there could be race conditions where two goroutines are issuing for the same
|
||||
// serial number at the same time.
|
||||
//
|
||||
// Returns the final certificate's bytes as DER.
|
||||
//
|
||||
// [issuance cycle]: https://github.com/letsencrypt/boulder/blob/main/docs/ISSUANCE-CYCLE.md
|
||||
func (ca *certificateAuthorityImpl) issueCertificateForPrecertificate(ctx context.Context,
|
||||
certProfile *certProfileWithID,
|
||||
precertDER []byte,
|
||||
sctBytes [][]byte,
|
||||
regID int64,
|
||||
orderID int64,
|
||||
) ([]byte, error) {
|
||||
precert, err := x509.ParseCertificate(precertDER)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
serialHex := core.SerialToString(precert.SerialNumber)
|
||||
if _, err = ca.sa.GetCertificate(ctx, &sapb.Serial{Serial: serialHex}); err == nil {
|
||||
err = berrors.InternalServerError("issuance of duplicate final certificate requested: %s", serialHex)
|
||||
ca.log.AuditErr(err.Error())
|
||||
return nil, err
|
||||
} else if !errors.Is(err, berrors.NotFound) {
|
||||
return nil, fmt.Errorf("error checking for duplicate issuance of %s: %s", serialHex, err)
|
||||
}
|
||||
var scts []ct.SignedCertificateTimestamp
|
||||
for _, singleSCTBytes := range sctBytes {
|
||||
var sct ct.SignedCertificateTimestamp
|
||||
_, err = cttls.Unmarshal(singleSCTBytes, &sct)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
scts = append(scts, sct)
|
||||
}
|
||||
|
||||
issuer, ok := ca.issuers.byNameID[issuance.IssuerNameID(precert)]
|
||||
if !ok {
|
||||
return nil, berrors.InternalServerError("no issuer found for Issuer Name %s", precert.Issuer)
|
||||
}
|
||||
|
||||
issuanceReq, err := issuance.RequestFromPrecert(precert, scts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
lintCertBytes, issuanceToken, err := issuer.Prepare(certProfile.profile, issuanceReq)
|
||||
if err != nil {
|
||||
ca.log.AuditErrf("Preparing cert failed: serial=[%s] err=[%v]", serialHex, err)
|
||||
return nil, berrors.InternalServerError("failed to prepare certificate signing: %s", err)
|
||||
}
|
||||
|
||||
logEvent := issuanceEvent{
|
||||
IssuanceRequest: issuanceReq,
|
||||
Issuer: issuer.Name(),
|
||||
OrderID: orderID,
|
||||
Profile: certProfile.name,
|
||||
Requester: regID,
|
||||
}
|
||||
ca.log.AuditObject("Signing cert", logEvent)
|
||||
|
||||
var ipStrings []string
|
||||
for _, ip := range issuanceReq.IPAddresses {
|
||||
ipStrings = append(ipStrings, ip.String())
|
||||
}
|
||||
|
||||
_, span := ca.tracer.Start(ctx, "signing cert", trace.WithAttributes(
|
||||
attribute.String("serial", serialHex),
|
||||
attribute.String("issuer", issuer.Name()),
|
||||
attribute.String("certProfileName", certProfile.name),
|
||||
attribute.StringSlice("names", issuanceReq.DNSNames),
|
||||
attribute.StringSlice("ipAddresses", ipStrings),
|
||||
))
|
||||
certDER, err := issuer.Issue(issuanceToken)
|
||||
if err != nil {
|
||||
ca.metrics.noteSignError(err)
|
||||
ca.log.AuditErrf("Signing cert failed: serial=[%s] err=[%v]", serialHex, err)
|
||||
span.SetStatus(codes.Error, err.Error())
|
||||
span.End()
|
||||
return nil, berrors.InternalServerError("failed to sign certificate: %s", err)
|
||||
}
|
||||
span.End()
|
||||
|
||||
err = tbsCertIsDeterministic(lintCertBytes, certDER)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ca.metrics.signatureCount.With(prometheus.Labels{"purpose": string(certType), "issuer": issuer.Name()}).Inc()
|
||||
ca.metrics.certificates.With(prometheus.Labels{"profile": certProfile.name}).Inc()
|
||||
logEvent.Result.Certificate = hex.EncodeToString(certDER)
|
||||
ca.log.AuditObject("Signing cert success", logEvent)
|
||||
|
||||
_, err = ca.sa.AddCertificate(ctx, &sapb.AddCertificateRequest{
|
||||
Der: certDER,
|
||||
RegID: regID,
|
||||
Issued: timestamppb.New(ca.clk.Now()),
|
||||
})
|
||||
if err != nil {
|
||||
ca.log.AuditErrf("Failed RPC to store at SA: serial=[%s] err=[%v]", serialHex, hex.EncodeToString(certDER))
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return certDER, nil
|
||||
}
|
||||
|
||||
// generateSerialNumber produces a big.Int which has more than 64 bits of
|
||||
// entropy and has the CA's configured one-byte prefix.
|
||||
func (ca *certificateAuthorityImpl) generateSerialNumber() (*big.Int, error) {
|
||||
// We want 136 bits of random number, plus an 8-bit instance id prefix.
|
||||
const randBits = 136
|
||||
serialBytes := make([]byte, randBits/8+1)
|
||||
serialBytes[0] = ca.prefix
|
||||
_, err := rand.Read(serialBytes[1:])
|
||||
if err != nil {
|
||||
err = berrors.InternalServerError("failed to generate serial: %s", err)
|
||||
ca.log.AuditErrf("Serial randomness failed, err=[%v]", err)
|
||||
return nil, err
|
||||
}
|
||||
serialBigInt := big.NewInt(0)
|
||||
serialBigInt = serialBigInt.SetBytes(serialBytes)
|
||||
|
||||
return serialBigInt, nil
|
||||
}
|
||||
|
||||
// generateSKID computes the Subject Key Identifier using one of the methods in
|
||||
// RFC 7093 Section 2 Additional Methods for Generating Key Identifiers:
|
||||
// The keyIdentifier [may be] composed of the leftmost 160-bits of the
|
||||
// SHA-256 hash of the value of the BIT STRING subjectPublicKey
|
||||
// (excluding the tag, length, and number of unused bits).
|
||||
func generateSKID(pk crypto.PublicKey) ([]byte, error) {
|
||||
pkBytes, err := x509.MarshalPKIXPublicKey(pk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var pkixPublicKey struct {
|
||||
Algo pkix.AlgorithmIdentifier
|
||||
BitString asn1.BitString
|
||||
}
|
||||
if _, err := asn1.Unmarshal(pkBytes, &pkixPublicKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
skid := sha256.Sum256(pkixPublicKey.BitString.Bytes)
|
||||
return skid[0:20:20], nil
|
||||
}
|
||||
|
||||
func (ca *certificateAuthorityImpl) issuePrecertificateInner(ctx context.Context, issueReq *capb.IssueCertificateRequest, certProfile *certProfileWithID, serialBigInt *big.Int, notBefore time.Time, notAfter time.Time) ([]byte, *certProfileWithID, error) {
|
||||
csr, err := x509.ParseCertificateRequest(issueReq.Csr)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
err = csrlib.VerifyCSR(ctx, csr, ca.maxNames, &ca.keyPolicy, ca.pa)
|
||||
if err != nil {
|
||||
ca.log.AuditErr(err.Error())
|
||||
// VerifyCSR returns berror instances that can be passed through as-is
|
||||
// without wrapping.
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Select which pool of issuers to use, based on the to-be-issued cert's key
|
||||
// type.
|
||||
alg := csr.PublicKeyAlgorithm
|
||||
|
||||
// Select a random issuer from among the active issuers of this key type.
|
||||
issuerPool, ok := ca.issuers.byAlg[alg]
|
||||
if !ok || len(issuerPool) == 0 {
|
||||
return nil, nil, berrors.InternalServerError("no issuers found for public key algorithm %s", csr.PublicKeyAlgorithm)
|
||||
}
|
||||
issuer := issuerPool[mrand.IntN(len(issuerPool))]
|
||||
|
||||
if issuer.Cert.NotAfter.Before(notAfter) {
|
||||
err = berrors.InternalServerError("cannot issue a certificate that expires after the issuer certificate")
|
||||
ca.log.AuditErr(err.Error())
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
subjectKeyId, err := generateSKID(csr.PublicKey)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("computing subject key ID: %w", err)
|
||||
}
|
||||
|
||||
serialHex := core.SerialToString(serialBigInt)
|
||||
|
||||
dnsNames, ipAddresses, err := identifier.FromCSR(csr).ToValues()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
req := &issuance.IssuanceRequest{
|
||||
PublicKey: issuance.MarshalablePublicKey{PublicKey: csr.PublicKey},
|
||||
SubjectKeyId: subjectKeyId,
|
||||
Serial: serialBigInt.Bytes(),
|
||||
DNSNames: dnsNames,
|
||||
IPAddresses: ipAddresses,
|
||||
CommonName: csrlib.CNFromCSR(csr),
|
||||
IncludeCTPoison: true,
|
||||
NotBefore: notBefore,
|
||||
NotAfter: notAfter,
|
||||
}
|
||||
|
||||
lintCertBytes, issuanceToken, err := issuer.Prepare(certProfile.profile, req)
|
||||
if err != nil {
|
||||
ca.log.AuditErrf("Preparing precert failed: serial=[%s] err=[%v]", serialHex, err)
|
||||
if errors.Is(err, linter.ErrLinting) {
|
||||
ca.metrics.lintErrorCount.Inc()
|
||||
}
|
||||
return nil, nil, berrors.InternalServerError("failed to prepare precertificate signing: %s", err)
|
||||
}
|
||||
|
||||
// Note: we write the linting certificate bytes to this table, rather than the precertificate
|
||||
// (which we audit log but do not put in the database). This is to ensure that even if there is
|
||||
// an error immediately after signing the precertificate, we have a record in the DB of what we
|
||||
// intended to sign, and can do revocations based on that. See #6807.
|
||||
// The name of the SA method ("AddPrecertificate") is a historical artifact.
|
||||
_, err = ca.sa.AddPrecertificate(context.Background(), &sapb.AddCertificateRequest{
|
||||
Der: lintCertBytes,
|
||||
RegID: issueReq.RegistrationID,
|
||||
Issued: timestamppb.New(ca.clk.Now()),
|
||||
IssuerNameID: int64(issuer.NameID()),
|
||||
OcspNotReady: true,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
logEvent := issuanceEvent{
|
||||
CSR: hex.EncodeToString(csr.Raw),
|
||||
IssuanceRequest: req,
|
||||
Issuer: issuer.Name(),
|
||||
Profile: certProfile.name,
|
||||
Requester: issueReq.RegistrationID,
|
||||
OrderID: issueReq.OrderID,
|
||||
}
|
||||
ca.log.AuditObject("Signing precert", logEvent)
|
||||
|
||||
var ipStrings []string
|
||||
for _, ip := range csr.IPAddresses {
|
||||
ipStrings = append(ipStrings, ip.String())
|
||||
}
|
||||
|
||||
_, span := ca.tracer.Start(ctx, "signing precert", trace.WithAttributes(
|
||||
attribute.String("serial", serialHex),
|
||||
attribute.String("issuer", issuer.Name()),
|
||||
attribute.String("certProfileName", certProfile.name),
|
||||
attribute.StringSlice("names", csr.DNSNames),
|
||||
attribute.StringSlice("ipAddresses", ipStrings),
|
||||
))
|
||||
certDER, err := issuer.Issue(issuanceToken)
|
||||
if err != nil {
|
||||
ca.metrics.noteSignError(err)
|
||||
ca.log.AuditErrf("Signing precert failed: serial=[%s] err=[%v]", serialHex, err)
|
||||
span.SetStatus(codes.Error, err.Error())
|
||||
span.End()
|
||||
return nil, nil, berrors.InternalServerError("failed to sign precertificate: %s", err)
|
||||
}
|
||||
span.End()
|
||||
|
||||
err = tbsCertIsDeterministic(lintCertBytes, certDER)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ca.metrics.signatureCount.With(prometheus.Labels{"purpose": string(precertType), "issuer": issuer.Name()}).Inc()
|
||||
|
||||
logEvent.Result.Precertificate = hex.EncodeToString(certDER)
|
||||
// The CSR is big and not that informative, so don't log it a second time.
|
||||
logEvent.CSR = ""
|
||||
ca.log.AuditObject("Signing precert success", logEvent)
|
||||
|
||||
return certDER, &certProfileWithID{certProfile.name, nil}, nil
|
||||
}
|
||||
|
||||
// verifyTBSCertIsDeterministic verifies that x509.CreateCertificate signing
|
||||
// operation is deterministic and produced identical DER bytes between the given
|
||||
// lint certificate and leaf certificate. If the DER byte equality check fails
|
||||
// it's mississuance, but it's better to know about the problem sooner than
|
||||
// later. The caller is responsible for passing the appropriate valid
|
||||
// certificate bytes in the correct position.
|
||||
func tbsCertIsDeterministic(lintCertBytes []byte, leafCertBytes []byte) error {
|
||||
if core.IsAnyNilOrZero(lintCertBytes, leafCertBytes) {
|
||||
return fmt.Errorf("lintCertBytes of leafCertBytes were nil")
|
||||
}
|
||||
|
||||
// extractTBSCertBytes is a partial copy of //crypto/x509/parser.go to
|
||||
// extract the RawTBSCertificate field from given DER bytes. It the
|
||||
// RawTBSCertificate field bytes or an error if the given bytes cannot be
|
||||
// parsed. This is far more performant than parsing the entire *Certificate
|
||||
// structure with x509.ParseCertificate().
|
||||
//
|
||||
// RFC 5280, Section 4.1
|
||||
// Certificate ::= SEQUENCE {
|
||||
// tbsCertificate TBSCertificate,
|
||||
// signatureAlgorithm AlgorithmIdentifier,
|
||||
// signatureValue BIT STRING }
|
||||
//
|
||||
// TBSCertificate ::= SEQUENCE {
|
||||
// ..
|
||||
extractTBSCertBytes := func(inputDERBytes *[]byte) ([]byte, error) {
|
||||
input := cryptobyte.String(*inputDERBytes)
|
||||
|
||||
// Extract the Certificate bytes
|
||||
if !input.ReadASN1(&input, cryptobyte_asn1.SEQUENCE) {
|
||||
return nil, errors.New("malformed certificate")
|
||||
}
|
||||
|
||||
var tbs cryptobyte.String
|
||||
// Extract the TBSCertificate bytes from the Certificate bytes
|
||||
if !input.ReadASN1(&tbs, cryptobyte_asn1.SEQUENCE) {
|
||||
return nil, errors.New("malformed tbs certificate")
|
||||
}
|
||||
|
||||
if tbs.Empty() {
|
||||
return nil, errors.New("parsed RawTBSCertificate field was empty")
|
||||
}
|
||||
|
||||
return tbs, nil
|
||||
}
|
||||
|
||||
lintRawTBSCert, err := extractTBSCertBytes(&lintCertBytes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("while extracting lint TBS cert: %w", err)
|
||||
}
|
||||
|
||||
leafRawTBSCert, err := extractTBSCertBytes(&leafCertBytes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("while extracting leaf TBS cert: %w", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(lintRawTBSCert, leafRawTBSCert) {
|
||||
return fmt.Errorf("mismatch between lintCert and leafCert RawTBSCertificate DER bytes: \"%x\" != \"%x\"", lintRawTBSCert, leafRawTBSCert)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
1144
third-party/github.com/letsencrypt/boulder/ca/ca_test.go
vendored
1144
third-party/github.com/letsencrypt/boulder/ca/ca_test.go
vendored
File diff suppressed because it is too large
Load diff
203
third-party/github.com/letsencrypt/boulder/ca/crl.go
vendored
203
third-party/github.com/letsencrypt/boulder/ca/crl.go
vendored
|
|
@ -1,203 +0,0 @@
|
|||
package ca
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
capb "github.com/letsencrypt/boulder/ca/proto"
|
||||
"github.com/letsencrypt/boulder/core"
|
||||
corepb "github.com/letsencrypt/boulder/core/proto"
|
||||
bcrl "github.com/letsencrypt/boulder/crl"
|
||||
"github.com/letsencrypt/boulder/issuance"
|
||||
blog "github.com/letsencrypt/boulder/log"
|
||||
)
|
||||
|
||||
type crlImpl struct {
|
||||
capb.UnsafeCRLGeneratorServer
|
||||
issuers map[issuance.NameID]*issuance.Issuer
|
||||
profile *issuance.CRLProfile
|
||||
maxLogLen int
|
||||
log blog.Logger
|
||||
metrics *caMetrics
|
||||
}
|
||||
|
||||
var _ capb.CRLGeneratorServer = (*crlImpl)(nil)
|
||||
|
||||
// NewCRLImpl returns a new object which fulfils the ca.proto CRLGenerator
|
||||
// interface. It uses the list of issuers to determine what issuers it can
|
||||
// issue CRLs from. lifetime sets the validity period (inclusive) of the
|
||||
// resulting CRLs.
|
||||
func NewCRLImpl(
|
||||
issuers []*issuance.Issuer,
|
||||
profileConfig issuance.CRLProfileConfig,
|
||||
maxLogLen int,
|
||||
logger blog.Logger,
|
||||
metrics *caMetrics,
|
||||
) (*crlImpl, error) {
|
||||
issuersByNameID := make(map[issuance.NameID]*issuance.Issuer, len(issuers))
|
||||
for _, issuer := range issuers {
|
||||
issuersByNameID[issuer.NameID()] = issuer
|
||||
}
|
||||
|
||||
profile, err := issuance.NewCRLProfile(profileConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("loading CRL profile: %w", err)
|
||||
}
|
||||
|
||||
return &crlImpl{
|
||||
issuers: issuersByNameID,
|
||||
profile: profile,
|
||||
maxLogLen: maxLogLen,
|
||||
log: logger,
|
||||
metrics: metrics,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ci *crlImpl) GenerateCRL(stream grpc.BidiStreamingServer[capb.GenerateCRLRequest, capb.GenerateCRLResponse]) error {
|
||||
var issuer *issuance.Issuer
|
||||
var req *issuance.CRLRequest
|
||||
rcs := make([]x509.RevocationListEntry, 0)
|
||||
|
||||
for {
|
||||
in, err := stream.Recv()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
switch payload := in.Payload.(type) {
|
||||
case *capb.GenerateCRLRequest_Metadata:
|
||||
if req != nil {
|
||||
return errors.New("got more than one metadata message")
|
||||
}
|
||||
|
||||
req, err = ci.metadataToRequest(payload.Metadata)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var ok bool
|
||||
issuer, ok = ci.issuers[issuance.NameID(payload.Metadata.IssuerNameID)]
|
||||
if !ok {
|
||||
return fmt.Errorf("got unrecognized IssuerNameID: %d", payload.Metadata.IssuerNameID)
|
||||
}
|
||||
|
||||
case *capb.GenerateCRLRequest_Entry:
|
||||
rc, err := ci.entryToRevokedCertificate(payload.Entry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rcs = append(rcs, *rc)
|
||||
|
||||
default:
|
||||
return errors.New("got empty or malformed message in input stream")
|
||||
}
|
||||
}
|
||||
|
||||
if req == nil {
|
||||
return errors.New("no crl metadata received")
|
||||
}
|
||||
|
||||
// Compute a unique ID for this issuer-number-shard combo, to tie together all
|
||||
// the audit log lines related to its issuance.
|
||||
logID := blog.LogLineChecksum(fmt.Sprintf("%d", issuer.NameID()) + req.Number.String() + fmt.Sprintf("%d", req.Shard))
|
||||
ci.log.AuditInfof(
|
||||
"Signing CRL: logID=[%s] issuer=[%s] number=[%s] shard=[%d] thisUpdate=[%s] numEntries=[%d]",
|
||||
logID, issuer.Cert.Subject.CommonName, req.Number.String(), req.Shard, req.ThisUpdate, len(rcs),
|
||||
)
|
||||
|
||||
if len(rcs) > 0 {
|
||||
builder := strings.Builder{}
|
||||
for i := range len(rcs) {
|
||||
if builder.Len() == 0 {
|
||||
fmt.Fprintf(&builder, "Signing CRL: logID=[%s] entries=[", logID)
|
||||
}
|
||||
|
||||
fmt.Fprintf(&builder, "%x:%d,", rcs[i].SerialNumber.Bytes(), rcs[i].ReasonCode)
|
||||
|
||||
if builder.Len() >= ci.maxLogLen {
|
||||
fmt.Fprint(&builder, "]")
|
||||
ci.log.AuditInfo(builder.String())
|
||||
builder = strings.Builder{}
|
||||
}
|
||||
}
|
||||
fmt.Fprint(&builder, "]")
|
||||
ci.log.AuditInfo(builder.String())
|
||||
}
|
||||
|
||||
req.Entries = rcs
|
||||
|
||||
crlBytes, err := issuer.IssueCRL(ci.profile, req)
|
||||
if err != nil {
|
||||
ci.metrics.noteSignError(err)
|
||||
return fmt.Errorf("signing crl: %w", err)
|
||||
}
|
||||
ci.metrics.signatureCount.With(prometheus.Labels{"purpose": "crl", "issuer": issuer.Name()}).Inc()
|
||||
|
||||
hash := sha256.Sum256(crlBytes)
|
||||
ci.log.AuditInfof(
|
||||
"Signing CRL success: logID=[%s] size=[%d] hash=[%x]",
|
||||
logID, len(crlBytes), hash,
|
||||
)
|
||||
|
||||
for i := 0; i < len(crlBytes); i += 1000 {
|
||||
j := i + 1000
|
||||
if j > len(crlBytes) {
|
||||
j = len(crlBytes)
|
||||
}
|
||||
err = stream.Send(&capb.GenerateCRLResponse{
|
||||
Chunk: crlBytes[i:j],
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if i%1000 == 0 {
|
||||
ci.log.Debugf("Wrote %d bytes to output stream", i*1000)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ci *crlImpl) metadataToRequest(meta *capb.CRLMetadata) (*issuance.CRLRequest, error) {
|
||||
if core.IsAnyNilOrZero(meta.IssuerNameID, meta.ThisUpdate, meta.ShardIdx) {
|
||||
return nil, errors.New("got incomplete metadata message")
|
||||
}
|
||||
thisUpdate := meta.ThisUpdate.AsTime()
|
||||
number := bcrl.Number(thisUpdate)
|
||||
|
||||
return &issuance.CRLRequest{
|
||||
Number: number,
|
||||
Shard: meta.ShardIdx,
|
||||
ThisUpdate: thisUpdate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ci *crlImpl) entryToRevokedCertificate(entry *corepb.CRLEntry) (*x509.RevocationListEntry, error) {
|
||||
serial, err := core.StringToSerial(entry.Serial)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if core.IsAnyNilOrZero(entry.RevokedAt) {
|
||||
return nil, errors.New("got empty or zero revocation timestamp")
|
||||
}
|
||||
revokedAt := entry.RevokedAt.AsTime()
|
||||
|
||||
return &x509.RevocationListEntry{
|
||||
SerialNumber: serial,
|
||||
RevocationTime: revokedAt,
|
||||
ReasonCode: int(entry.Reason),
|
||||
}, nil
|
||||
}
|
||||
|
|
@ -1,271 +0,0 @@
|
|||
package ca
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"io"
|
||||
"testing"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
capb "github.com/letsencrypt/boulder/ca/proto"
|
||||
corepb "github.com/letsencrypt/boulder/core/proto"
|
||||
"github.com/letsencrypt/boulder/test"
|
||||
)
|
||||
|
||||
type mockGenerateCRLBidiStream struct {
|
||||
grpc.ServerStream
|
||||
input <-chan *capb.GenerateCRLRequest
|
||||
output chan<- *capb.GenerateCRLResponse
|
||||
}
|
||||
|
||||
func (s mockGenerateCRLBidiStream) Recv() (*capb.GenerateCRLRequest, error) {
|
||||
next, ok := <-s.input
|
||||
if !ok {
|
||||
return nil, io.EOF
|
||||
}
|
||||
return next, nil
|
||||
}
|
||||
|
||||
func (s mockGenerateCRLBidiStream) Send(entry *capb.GenerateCRLResponse) error {
|
||||
s.output <- entry
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestGenerateCRL(t *testing.T) {
|
||||
t.Parallel()
|
||||
testCtx := setup(t)
|
||||
crli := testCtx.crl
|
||||
errs := make(chan error, 1)
|
||||
|
||||
// Test that we get an error when no metadata is sent.
|
||||
ins := make(chan *capb.GenerateCRLRequest)
|
||||
go func() {
|
||||
errs <- crli.GenerateCRL(mockGenerateCRLBidiStream{input: ins, output: nil})
|
||||
}()
|
||||
close(ins)
|
||||
err := <-errs
|
||||
test.AssertError(t, err, "can't generate CRL with no metadata")
|
||||
test.AssertContains(t, err.Error(), "no crl metadata received")
|
||||
|
||||
// Test that we get an error when incomplete metadata is sent.
|
||||
ins = make(chan *capb.GenerateCRLRequest)
|
||||
go func() {
|
||||
errs <- crli.GenerateCRL(mockGenerateCRLBidiStream{input: ins, output: nil})
|
||||
}()
|
||||
ins <- &capb.GenerateCRLRequest{
|
||||
Payload: &capb.GenerateCRLRequest_Metadata{
|
||||
Metadata: &capb.CRLMetadata{},
|
||||
},
|
||||
}
|
||||
close(ins)
|
||||
err = <-errs
|
||||
test.AssertError(t, err, "can't generate CRL with incomplete metadata")
|
||||
test.AssertContains(t, err.Error(), "got incomplete metadata message")
|
||||
|
||||
// Test that we get an error when unrecognized metadata is sent.
|
||||
ins = make(chan *capb.GenerateCRLRequest)
|
||||
go func() {
|
||||
errs <- crli.GenerateCRL(mockGenerateCRLBidiStream{input: ins, output: nil})
|
||||
}()
|
||||
now := testCtx.fc.Now()
|
||||
ins <- &capb.GenerateCRLRequest{
|
||||
Payload: &capb.GenerateCRLRequest_Metadata{
|
||||
Metadata: &capb.CRLMetadata{
|
||||
IssuerNameID: 1,
|
||||
ThisUpdate: timestamppb.New(now),
|
||||
ShardIdx: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
close(ins)
|
||||
err = <-errs
|
||||
test.AssertError(t, err, "can't generate CRL with bad metadata")
|
||||
test.AssertContains(t, err.Error(), "got unrecognized IssuerNameID")
|
||||
|
||||
// Test that we get an error when two metadata are sent.
|
||||
ins = make(chan *capb.GenerateCRLRequest)
|
||||
go func() {
|
||||
errs <- crli.GenerateCRL(mockGenerateCRLBidiStream{input: ins, output: nil})
|
||||
}()
|
||||
ins <- &capb.GenerateCRLRequest{
|
||||
Payload: &capb.GenerateCRLRequest_Metadata{
|
||||
Metadata: &capb.CRLMetadata{
|
||||
IssuerNameID: int64(testCtx.boulderIssuers[0].NameID()),
|
||||
ThisUpdate: timestamppb.New(now),
|
||||
ShardIdx: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
ins <- &capb.GenerateCRLRequest{
|
||||
Payload: &capb.GenerateCRLRequest_Metadata{
|
||||
Metadata: &capb.CRLMetadata{
|
||||
IssuerNameID: int64(testCtx.boulderIssuers[0].NameID()),
|
||||
ThisUpdate: timestamppb.New(now),
|
||||
ShardIdx: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
close(ins)
|
||||
err = <-errs
|
||||
fmt.Println("done waiting for error")
|
||||
test.AssertError(t, err, "can't generate CRL with duplicate metadata")
|
||||
test.AssertContains(t, err.Error(), "got more than one metadata message")
|
||||
|
||||
// Test that we get an error when an entry has a bad serial.
|
||||
ins = make(chan *capb.GenerateCRLRequest)
|
||||
go func() {
|
||||
errs <- crli.GenerateCRL(mockGenerateCRLBidiStream{input: ins, output: nil})
|
||||
}()
|
||||
ins <- &capb.GenerateCRLRequest{
|
||||
Payload: &capb.GenerateCRLRequest_Entry{
|
||||
Entry: &corepb.CRLEntry{
|
||||
Serial: "123",
|
||||
Reason: 1,
|
||||
RevokedAt: timestamppb.New(now),
|
||||
},
|
||||
},
|
||||
}
|
||||
close(ins)
|
||||
err = <-errs
|
||||
test.AssertError(t, err, "can't generate CRL with bad serials")
|
||||
test.AssertContains(t, err.Error(), "invalid serial number")
|
||||
|
||||
// Test that we get an error when an entry has a bad revocation time.
|
||||
ins = make(chan *capb.GenerateCRLRequest)
|
||||
go func() {
|
||||
errs <- crli.GenerateCRL(mockGenerateCRLBidiStream{input: ins, output: nil})
|
||||
}()
|
||||
|
||||
ins <- &capb.GenerateCRLRequest{
|
||||
Payload: &capb.GenerateCRLRequest_Entry{
|
||||
Entry: &corepb.CRLEntry{
|
||||
Serial: "deadbeefdeadbeefdeadbeefdeadbeefdead",
|
||||
Reason: 1,
|
||||
RevokedAt: nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
close(ins)
|
||||
err = <-errs
|
||||
test.AssertError(t, err, "can't generate CRL with bad serials")
|
||||
test.AssertContains(t, err.Error(), "got empty or zero revocation timestamp")
|
||||
|
||||
// Test that generating an empty CRL works.
|
||||
ins = make(chan *capb.GenerateCRLRequest)
|
||||
outs := make(chan *capb.GenerateCRLResponse)
|
||||
go func() {
|
||||
errs <- crli.GenerateCRL(mockGenerateCRLBidiStream{input: ins, output: outs})
|
||||
close(outs)
|
||||
}()
|
||||
crlBytes := make([]byte, 0)
|
||||
done := make(chan struct{})
|
||||
go func() {
|
||||
for resp := range outs {
|
||||
crlBytes = append(crlBytes, resp.Chunk...)
|
||||
}
|
||||
close(done)
|
||||
}()
|
||||
ins <- &capb.GenerateCRLRequest{
|
||||
Payload: &capb.GenerateCRLRequest_Metadata{
|
||||
Metadata: &capb.CRLMetadata{
|
||||
IssuerNameID: int64(testCtx.boulderIssuers[0].NameID()),
|
||||
ThisUpdate: timestamppb.New(now),
|
||||
ShardIdx: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
close(ins)
|
||||
err = <-errs
|
||||
<-done
|
||||
test.AssertNotError(t, err, "generating empty CRL should work")
|
||||
test.Assert(t, len(crlBytes) > 0, "should have gotten some CRL bytes")
|
||||
crl, err := x509.ParseRevocationList(crlBytes)
|
||||
test.AssertNotError(t, err, "should be able to parse empty CRL")
|
||||
test.AssertEquals(t, len(crl.RevokedCertificateEntries), 0)
|
||||
err = crl.CheckSignatureFrom(testCtx.boulderIssuers[0].Cert.Certificate)
|
||||
test.AssertEquals(t, crl.ThisUpdate, now)
|
||||
test.AssertEquals(t, crl.ThisUpdate, timestamppb.New(now).AsTime())
|
||||
test.AssertNotError(t, err, "CRL signature should validate")
|
||||
|
||||
// Test that generating a CRL with some entries works.
|
||||
ins = make(chan *capb.GenerateCRLRequest)
|
||||
outs = make(chan *capb.GenerateCRLResponse)
|
||||
go func() {
|
||||
errs <- crli.GenerateCRL(mockGenerateCRLBidiStream{input: ins, output: outs})
|
||||
close(outs)
|
||||
}()
|
||||
crlBytes = make([]byte, 0)
|
||||
done = make(chan struct{})
|
||||
go func() {
|
||||
for resp := range outs {
|
||||
crlBytes = append(crlBytes, resp.Chunk...)
|
||||
}
|
||||
close(done)
|
||||
}()
|
||||
ins <- &capb.GenerateCRLRequest{
|
||||
Payload: &capb.GenerateCRLRequest_Metadata{
|
||||
Metadata: &capb.CRLMetadata{
|
||||
IssuerNameID: int64(testCtx.boulderIssuers[0].NameID()),
|
||||
ThisUpdate: timestamppb.New(now),
|
||||
ShardIdx: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
ins <- &capb.GenerateCRLRequest{
|
||||
Payload: &capb.GenerateCRLRequest_Entry{
|
||||
Entry: &corepb.CRLEntry{
|
||||
Serial: "000000000000000000000000000000000000",
|
||||
RevokedAt: timestamppb.New(now),
|
||||
// Reason 0, Unspecified, is omitted.
|
||||
},
|
||||
},
|
||||
}
|
||||
ins <- &capb.GenerateCRLRequest{
|
||||
Payload: &capb.GenerateCRLRequest_Entry{
|
||||
Entry: &corepb.CRLEntry{
|
||||
Serial: "111111111111111111111111111111111111",
|
||||
Reason: 1, // keyCompromise
|
||||
RevokedAt: timestamppb.New(now),
|
||||
},
|
||||
},
|
||||
}
|
||||
ins <- &capb.GenerateCRLRequest{
|
||||
Payload: &capb.GenerateCRLRequest_Entry{
|
||||
Entry: &corepb.CRLEntry{
|
||||
Serial: "444444444444444444444444444444444444",
|
||||
Reason: 4, // superseded
|
||||
RevokedAt: timestamppb.New(now),
|
||||
},
|
||||
},
|
||||
}
|
||||
ins <- &capb.GenerateCRLRequest{
|
||||
Payload: &capb.GenerateCRLRequest_Entry{
|
||||
Entry: &corepb.CRLEntry{
|
||||
Serial: "555555555555555555555555555555555555",
|
||||
Reason: 5, // cessationOfOperation
|
||||
RevokedAt: timestamppb.New(now),
|
||||
},
|
||||
},
|
||||
}
|
||||
ins <- &capb.GenerateCRLRequest{
|
||||
Payload: &capb.GenerateCRLRequest_Entry{
|
||||
Entry: &corepb.CRLEntry{
|
||||
Serial: "999999999999999999999999999999999999",
|
||||
Reason: 9, // privilegeWithdrawn
|
||||
RevokedAt: timestamppb.New(now),
|
||||
},
|
||||
},
|
||||
}
|
||||
close(ins)
|
||||
err = <-errs
|
||||
<-done
|
||||
test.AssertNotError(t, err, "generating empty CRL should work")
|
||||
test.Assert(t, len(crlBytes) > 0, "should have gotten some CRL bytes")
|
||||
crl, err = x509.ParseRevocationList(crlBytes)
|
||||
test.AssertNotError(t, err, "should be able to parse empty CRL")
|
||||
test.AssertEquals(t, len(crl.RevokedCertificateEntries), 5)
|
||||
err = crl.CheckSignatureFrom(testCtx.boulderIssuers[0].Cert.Certificate)
|
||||
test.AssertNotError(t, err, "CRL signature should validate")
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue