Merge branch 'main' into github_identity_provider

This commit is contained in:
Ryan Richard
2024-05-07 13:08:50 -07:00
25 changed files with 228 additions and 620 deletions

View File

@@ -152,6 +152,29 @@ go build -o pinniped ./cmd/pinniped
To destroy the local Kubernetes cluster, run `./hack/kind-down.sh`.
#### Using GoLand to Run an Integration Test
It can sometimes be convenient to use GoLand to run an integration test. For example, this allows using the
GoLand debugger to debug the test itself (not the server, since that it running in-cluster).
Note that the output of `hack/prepare-for-integration-tests.sh` says:
```bash
# Using GoLand? Paste the result of this command into GoLand's run configuration "Environment".
# hack/integration-test-env-goland.sh | pbcopy
```
After using `hack/prepare-for-integration-tests.sh`, run `hack/integration-test-env-goland.sh | pbcopy` as instructed. Then:
1. Select and run an integration test within GoLand. It will fail complaining about missing env vars.
1. Pull down the menu that shows the name of the test which you just ran in the previous step, and choose "Edit Configurations...".
1. In the "Environment" text box for the run configuration of the integration test that you just ran,
paste the results of `hack/integration-test-env-goland.sh | pbcopy`.
1. Apply, and then run the integration test again. This time the test will use the environment variables provided.
Note that if you run `hack/prepare-for-integration-tests.sh` again, then you may need to repeat these steps.
Each run of `hack/prepare-for-integration-tests.sh` can result in different values for some of the env vars.
### Observing Tests on the Continuous Integration Environment
[CI](https://ci.pinniped.dev/teams/main/pipelines/pull-requests)

View File

@@ -3,8 +3,8 @@
# Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
ARG BUILD_IMAGE=golang:1.22.2@sha256:450e3822c7a135e1463cd83e51c8e2eb03b86a02113c89424e6f0f8344bb4168
ARG BASE_IMAGE=gcr.io/distroless/static:nonroot@sha256:f41b84cda410b05cc690c2e33d1973a31c6165a2721e2b5343aab50fecb63441
ARG BUILD_IMAGE=golang:1.22.2@sha256:d5302d40dc5fbbf38ec472d1848a9d2391a13f93293a6a5b0b87c99dc0eaa6ae
ARG BASE_IMAGE=gcr.io/distroless/static:nonroot@sha256:e9ac71e2b8e279a8372741b7a0293afda17650d926900233ec3a7b2b7c22a246
# Prepare to cross-compile by always running the build stage in the build platform, not the target platform.
FROM --platform=$BUILDPLATFORM $BUILD_IMAGE as build-env

View File

@@ -1,4 +1,4 @@
#! Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
#! Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
#! SPDX-License-Identifier: Apache-2.0
#@ load("@ytt:data", "data")
@@ -96,14 +96,9 @@ data:
imagePullSecrets:
- image-pull-secret
(@ end @)
(@ if data.values.log_level or data.values.deprecated_log_format: @)
(@ if data.values.log_level: @)
log:
(@ if data.values.log_level: @)
level: (@= getAndValidateLogLevel() @)
(@ end @)
(@ if data.values.deprecated_log_format: @)
format: (@= data.values.deprecated_log_format @)
(@ end @)
(@ end @)
---
#@ if data.values.image_pull_dockerconfigjson and data.values.image_pull_dockerconfigjson != "":

View File

@@ -124,17 +124,6 @@ api_serving_certificate_renew_before_seconds: 2160000
#@schema/validation one_of=["info", "debug", "trace", "all"]
log_level: ""
#@schema/title "Log format"
#@ deprecated_log_format_desc = "Specify the format of logging: json (for machine parsable logs) and text (for legacy klog formatted logs). \
#@ By default, when this value is left unset, logs are formatted in json. \
#@ This configuration is deprecated and will be removed in a future release at which point logs will always be formatted as json."
#@schema/desc deprecated_log_format_desc
#@schema/examples ("Set logs to JSON format","json")
#@schema/nullable
#@schema/validation one_of=["json", "text"]
#@schema/deprecated "This configuration is deprecated and will be removed in a future release at which point logs will always be formatted as json."
deprecated_log_format: ""
#@schema/title "Run as user"
#@schema/desc "The user ID that will own the process."
#! See the Dockerfile for the reasoning behind this default value.

View File

@@ -1,4 +1,4 @@
#! Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
#! Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
#! SPDX-License-Identifier: Apache-2.0
#@ load("@ytt:data", "data")
@@ -53,17 +53,11 @@ _: #@ template.replace(data.values.custom_labels)
#@ "apiService": defaultResourceNameWithSuffix("api"),
#@ },
#@ "labels": labels(),
#@ "insecureAcceptExternalUnencryptedHttpRequests": data.values.deprecated_insecure_accept_external_unencrypted_http_requests
#@ }
#@ if data.values.log_level or data.values.deprecated_log_format:
#@ config["log"] = {}
#@ end
#@ if data.values.log_level:
#@ config["log"] = {}
#@ config["log"]["level"] = getAndValidateLogLevel()
#@ end
#@ if data.values.deprecated_log_format:
#@ config["log"]["format"] = data.values.deprecated_log_format
#@ end
#@ if data.values.endpoints:
#@ config["endpoints"] = data.values.endpoints
#@ end

View File

@@ -1,24 +1,10 @@
#! Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
#! Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
#! SPDX-License-Identifier: Apache-2.0
#@ load("@ytt:data", "data")
#@ load("@ytt:assert", "assert")
#@ load("helpers.lib.yaml", "labels", "deploymentPodLabel", "namespace", "defaultResourceName", "defaultResourceNameWithSuffix")
#@ if hasattr(data.values, "service_http_nodeport_port"):
#@ assert.fail('value "service_http_nodeport_port" has been renamed to "deprecated_service_http_nodeport_port" and will be removed in a future release')
#@ end
#@ if hasattr(data.values, "service_http_nodeport_nodeport"):
#@ assert.fail('value "service_http_nodeport_nodeport" has been renamed to "deprecated_service_http_nodeport_nodeport" and will be removed in a future release')
#@ end
#@ if hasattr(data.values, "service_http_loadbalancer_port"):
#@ assert.fail('value "service_http_loadbalancer_port" has been renamed to "deprecated_service_http_loadbalancer_port" and will be removed in a future release')
#@ end
#@ if hasattr(data.values, "service_http_clusterip_port"):
#@ assert.fail('value "service_http_clusterip_port" has been renamed to "deprecated_service_http_clusterip_port" and will be removed in a future release')
#@ end
#@ if data.values.deprecated_service_http_nodeport_port or data.values.service_https_nodeport_port:
#@ if data.values.service_https_nodeport_port:
---
apiVersion: v1
kind: Service
@@ -33,15 +19,6 @@ spec:
type: NodePort
selector: #@ deploymentPodLabel()
ports:
#@ if data.values.deprecated_service_http_nodeport_port:
- name: http
protocol: TCP
port: #@ data.values.deprecated_service_http_nodeport_port
targetPort: 8080
#@ if data.values.deprecated_service_http_nodeport_nodeport:
nodePort: #@ data.values.deprecated_service_http_nodeport_nodeport
#@ end
#@ end
#@ if data.values.service_https_nodeport_port:
- name: https
protocol: TCP
@@ -53,7 +30,7 @@ spec:
#@ end
#@ end
#@ if data.values.deprecated_service_http_clusterip_port or data.values.service_https_clusterip_port:
#@ if data.values.service_https_clusterip_port:
---
apiVersion: v1
kind: Service
@@ -68,12 +45,6 @@ spec:
type: ClusterIP
selector: #@ deploymentPodLabel()
ports:
#@ if data.values.deprecated_service_http_clusterip_port:
- name: http
protocol: TCP
port: #@ data.values.deprecated_service_http_clusterip_port
targetPort: 8080
#@ end
#@ if data.values.service_https_clusterip_port:
- name: https
protocol: TCP
@@ -82,7 +53,7 @@ spec:
#@ end
#@ end
#@ if data.values.deprecated_service_http_loadbalancer_port or data.values.service_https_loadbalancer_port:
#@ if data.values.service_https_loadbalancer_port:
---
apiVersion: v1
kind: Service
@@ -100,12 +71,6 @@ spec:
loadBalancerIP: #@ data.values.service_loadbalancer_ip
#@ end
ports:
#@ if data.values.deprecated_service_http_loadbalancer_port:
- name: http
protocol: TCP
port: #@ data.values.deprecated_service_http_loadbalancer_port
targetPort: 8080
#@ end
#@ if data.values.service_https_loadbalancer_port:
- name: https
protocol: TCP

View File

@@ -79,34 +79,6 @@ image_tag: latest
#@schema/validation min_len=1
image_pull_dockerconfigjson: ""
#@schema/title "Deprecated service HTTP nodeport port"
#@schema/desc "When specified, creates a NodePort Service with this `port` value, with port 8080 as its `targetPort`"
#@schema/examples ("Specify port",31234)
#@schema/nullable
#@schema/deprecated "This data value will be removed in a future release"
deprecated_service_http_nodeport_port: 0
#@schema/title "Deprecated service http nodeport nodeport"
#@schema/desc "The `nodePort` value of the NodePort Service, optional when `deprecated_service_http_nodeport_port` is specified"
#@schema/examples ("Specify port",31234)
#@schema/nullable
#@schema/deprecated "This data value will be removed in a future release"
deprecated_service_http_nodeport_nodeport: 0
#@schema/title "Deprecated service http loadbalancer port"
#@schema/desc "When specified, creates a LoadBalancer Service with this `port` value, with port 8080 as its `targetPort`"
#@schema/examples ("Specify port",8443)
#@schema/nullable
#@schema/deprecated "This data value will be removed in a future release"
deprecated_service_http_loadbalancer_port: 0
#@schema/title "Deprecated service http clusterip port"
#@schema/desc "Creates a ClusterIP Service with this `port` value, with port 8080 as its `targetPort`"
#@schema/examples ("Specify port",8443)
#@schema/nullable
#@schema/deprecated "This data value will be removed in a future release"
deprecated_service_http_clusterip_port: 0
#@schema/title "Service https nodeport port"
#@schema/desc "When specified, creates a NodePort Service with this `port` value, with port 8443 as its `targetPort`"
#@schema/examples ("Specify port",31243)
@@ -147,17 +119,6 @@ service_loadbalancer_ip: ""
#@schema/validation one_of=["info", "debug", "trace", "all"]
log_level: ""
#@schema/title "Log format"
#@ deprecated_log_format_desc = "Specify the format of logging: json (for machine parsable logs) and text (for legacy klog formatted logs). \
#@ By default, when this value is left unset, logs are formatted in json. \
#@ This configuration is deprecated and will be removed in a future release at which point logs will always be formatted as json."
#@schema/desc deprecated_log_format_desc
#@schema/examples ("Set logs to JSON format","json")
#@schema/nullable
#@schema/validation one_of=["json", "text"]
#@schema/deprecated "This configuration is deprecated and will be removed in a future release at which point logs will always be formatted as json."
deprecated_log_format: ""
#@schema/title "Run as user"
#@schema/desc "The user ID that will own the process."
#! See the Dockerfile for the reasoning behind this default value.
@@ -242,19 +203,3 @@ no_proxy: "$(KUBERNETES_SERVICE_HOST),169.254.169.254,127.0.0.1,localhost,.svc,.
#@schema/nullable
#@schema/validation ("a map with keys 'http' and 'https', whose values are either the string 'disabled' or a map having keys 'network' and 'address', and the value of 'network' must be one of the allowed values", validate_endpoints)
endpoints: { }
#@ deprecated_insecure_accept_external_unencrypted_http_requests_desc = "Optionally override the validation on the endpoints.http \
#@ value which checks that only loopback interfaces are used. \
#@ When deprecated_insecure_accept_external_unencrypted_http_requests is true, the HTTP listener is allowed to bind to any \
#@ interface, including interfaces that are listening for traffic from outside the pod. This value is being introduced \
#@ to ease the transition to the new loopback interface validation for the HTTP port for any users who need more time \
#@ to change their ingress strategy to avoid using plain HTTP into the Supervisor pods. \
#@ This value is immediately deprecated upon its introduction. It will be removed in some future release, at which time \
#@ traffic from outside the pod will need to be sent to the HTTPS listener instead, with no simple workaround available. \
#@ Allowed values are true (boolean), 'true' (string), false (boolean), and 'false' (string). The default is false."
#@schema/desc deprecated_insecure_accept_external_unencrypted_http_requests_desc
#@schema/type any=True
#@schema/validation ("a boolean or string version of boolean", lambda v: type(v) in ["string", "boolean"])
#@schema/validation one_of=["true", "false", True, False]
#@schema/deprecated "This data value will be removed in a future release"
deprecated_insecure_accept_external_unencrypted_http_requests: false

37
go.mod
View File

@@ -4,12 +4,12 @@ go 1.22.0
toolchain go1.22.2
// This version taken from https://github.com/kubernetes/apiserver/blob/v0.29.2/go.mod#L14 to avoid compile failures.
replace github.com/google/cel-go => github.com/google/cel-go v0.17.7
// This version taken from https://github.com/kubernetes/apiserver/blob/v0.30.0/go.mod#L14 to avoid compile failures.
replace github.com/google/cel-go => github.com/google/cel-go v0.17.8
// ory/fosite depends on ory/x which depends on opentelemetry. kubernetes/apiserver also depends on opentelemetry.
// Where they clash and cause "go mod tidy" to fail, use replace directives to make it work.
// Copied from https://github.com/kubernetes/apiserver/blob/v0.29.2/go.mod#L28-L33.
// Copied from https://github.com/kubernetes/apiserver/blob/v0.30.0/go.mod#L29-L34.
replace (
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc => go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.42.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp => go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.44.0
@@ -19,23 +19,20 @@ replace (
go.opentelemetry.io/otel/trace => go.opentelemetry.io/otel/trace v1.19.0
)
// https://github.com/kubernetes/apiserver/blob/v0.29.2/go.mod does not include this one, but it is also needed
// https://github.com/kubernetes/apiserver/blob/v0.30.0/go.mod does not include this one, but it is also needed
// to resolve the clashes with ory/x, so use the same version that kubernetes/apiserver chooses for opentelemetry.
replace go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp => go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0
// This is an indirect dep which has CVE-2023-45142, so replace it with the fixed version.
replace go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace => go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.44.0
// This is an indirect dep which has CVE-2024-24786, so replace it with a fixed version
replace google.golang.org/protobuf => google.golang.org/protobuf v1.33.0
// https://github.com/coreos/go-oidc/releases/tag/v3.10.0 starts to use https://github.com/go-jose/go-jose/releases/tag/v4.0.0.
// Unfortunately this has breaking changes.
replace github.com/coreos/go-oidc/v3 => github.com/coreos/go-oidc/v3 v3.9.0
require (
github.com/MakeNowJust/heredoc/v2 v2.0.1
github.com/chromedp/cdproto v0.0.0-20240421230201-ab917191657d
github.com/chromedp/cdproto v0.0.0-20240501202034-ef67d660e9fd
github.com/chromedp/chromedp v0.9.5
github.com/coreos/go-oidc/v3 v3.10.0
github.com/coreos/go-semver v0.3.1
@@ -63,15 +60,15 @@ require (
github.com/spf13/cobra v1.8.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.9.0
github.com/tdewolff/minify/v2 v2.20.19
github.com/tdewolff/minify/v2 v2.20.20
go.uber.org/mock v0.4.0
go.uber.org/zap v1.27.0
golang.org/x/crypto v0.22.0
golang.org/x/net v0.24.0
golang.org/x/oauth2 v0.19.0
golang.org/x/crypto v0.23.0
golang.org/x/net v0.25.0
golang.org/x/oauth2 v0.20.0
golang.org/x/sync v0.7.0
golang.org/x/term v0.19.0
golang.org/x/text v0.14.0
golang.org/x/term v0.20.0
golang.org/x/text v0.15.0
k8s.io/api v0.30.0
k8s.io/apiextensions-apiserver v0.30.0
k8s.io/apimachinery v0.30.0
@@ -81,8 +78,8 @@ require (
k8s.io/gengo v0.0.0-20240404160639-a0386bf69313
k8s.io/klog/v2 v2.120.1
k8s.io/kube-aggregator v0.30.0
k8s.io/kube-openapi v0.0.0-20240411171206-dc4e619f62f3
k8s.io/utils v0.0.0-20240310230437-4693a0247e57
k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f
k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0
sigs.k8s.io/yaml v1.4.0
)
@@ -163,7 +160,7 @@ require (
github.com/spf13/viper v1.16.0 // indirect
github.com/stoewer/go-strcase v1.2.0 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/tdewolff/parse/v2 v2.7.12 // indirect
github.com/tdewolff/parse/v2 v2.7.13 // indirect
go.etcd.io/etcd/api/v3 v3.5.10 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.10 // indirect
go.etcd.io/etcd/client/v3 v3.5.10 // indirect
@@ -185,10 +182,10 @@ require (
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc // indirect
golang.org/x/mod v0.15.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.18.0 // indirect
golang.org/x/tools v0.20.0 // indirect
google.golang.org/genproto v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230822172742-b8732ec3820d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d // indirect

91
go.sum
View File

@@ -25,9 +25,8 @@ cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUM
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY=
cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc=
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
@@ -70,8 +69,8 @@ github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chromedp/cdproto v0.0.0-20240202021202-6d0b6a386732/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
github.com/chromedp/cdproto v0.0.0-20240421230201-ab917191657d h1:x9d0XwRV3aWw1gAZtv0LrI39U+Efjp0mtyXRyikGb9Y=
github.com/chromedp/cdproto v0.0.0-20240421230201-ab917191657d/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
github.com/chromedp/cdproto v0.0.0-20240501202034-ef67d660e9fd h1:5/HXKq8EaAWVmnl6Hnyl4SVq7FF5990DBW6AuTrWtVw=
github.com/chromedp/cdproto v0.0.0-20240501202034-ef67d660e9fd/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
github.com/chromedp/chromedp v0.9.5 h1:viASzruPJOiThk7c5bueOUY91jGLJVximoEMGoH93rg=
github.com/chromedp/chromedp v0.9.5/go.mod h1:D4I2qONslauw/C7INoCir1BJkSwBYMyZgx8X276z3+Y=
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
@@ -172,7 +171,8 @@ github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/gobuffalo/attrs v1.0.3/go.mod h1:KvDJCE0avbufqS0Bw3UV7RQynESY0jjod+572ctX4t8=
github.com/gobuffalo/envy v1.10.2/go.mod h1:qGAGwdvDsaEtPhfBzb3o0SfDea8ByGn9j8bKmVft9z8=
github.com/gobuffalo/fizz v1.14.4/go.mod h1:9/2fGNXNeIFOXEEgTPJwiK63e44RjG+Nc4hfMm1ArGM=
@@ -227,19 +227,22 @@ github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/cel-go v0.17.7 h1:6ebJFzu1xO2n7TLtN+UBqShGBhlD85bhvglh5DpcfqQ=
github.com/google/cel-go v0.17.7/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY=
github.com/google/cel-go v0.17.8 h1:j9m730pMZt1Fc4oKhCLUHfjj6527LuhYcYw0Rl8gqto=
github.com/google/cel-go v0.17.8/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -251,7 +254,6 @@ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
@@ -272,8 +274,8 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20221010195024-131d412537ea h1:R3VfsTXMMK4JCWZDdxScmnTzu9n9YRsDvguLis0U/b8=
github.com/google/pprof v0.0.0-20221010195024-131d412537ea/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
@@ -462,10 +464,10 @@ github.com/nyaruka/phonenumbers v1.1.1/go.mod h1:cGaEsOrLjIL0iKGqJR5Rfywy86dSkbA
github.com/oleiade/reflections v1.0.1 h1:D1XO3LVEYroYskEsoSiGItp9RUxG6jWnCVvrqH0HHQM=
github.com/oleiade/reflections v1.0.1/go.mod h1:rdFxbxq4QXVZWj0F+e9jqjDkc7dbp97vkRixKo2JR60=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY=
github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM=
github.com/onsi/gomega v1.31.0 h1:54UJxxj6cPInHS3a35wm6BK/F9nHYueZ1NVujHDrnXE=
github.com/onsi/gomega v1.31.0/go.mod h1:DW9aCi7U6Yi40wNVAvT6kzFnEVEI5n3DloYBiKiT6zk=
github.com/onsi/ginkgo/v2 v2.17.2 h1:7eMhcy3GimbsA3hEnVKdw/PQM9XN9krpKVXsZdph0/g=
github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
github.com/openzipkin/zipkin-go v0.4.1 h1:kNd/ST2yLLWhaWrkgchya40TJabe8Hioj9udfPcEO5A=
github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
@@ -565,10 +567,10 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
github.com/tdewolff/minify/v2 v2.20.19 h1:tX0SR0LUrIqGoLjXnkIzRSIbKJ7PaNnSENLD4CyH6Xo=
github.com/tdewolff/minify/v2 v2.20.19/go.mod h1:ulkFoeAVWMLEyjuDz1ZIWOA31g5aWOawCFRp9R/MudM=
github.com/tdewolff/parse/v2 v2.7.12 h1:tgavkHc2ZDEQVKy1oWxwIyh5bP4F5fEh/JmBwPP/3LQ=
github.com/tdewolff/parse/v2 v2.7.12/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA=
github.com/tdewolff/minify/v2 v2.20.20 h1:vhULb+VsW2twkplgsawAoUY957efb+EdiZ7zu5fUhhk=
github.com/tdewolff/minify/v2 v2.20.20/go.mod h1:GYaLXFpIIwsX99apQHXfGdISUdlA98wmaoWxjT9C37k=
github.com/tdewolff/parse/v2 v2.7.13 h1:iSiwOUkCYLNfapHoqdLcqZVgvQ0jrsao8YYKP/UJYTI=
github.com/tdewolff/parse/v2 v2.7.13/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA=
github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03u/dMQK9g+Iw9ewps4mCl1nB8Sscbo=
github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
@@ -682,8 +684,8 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -723,8 +725,8 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -768,8 +770,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -779,8 +781,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo=
golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -855,8 +857,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -866,8 +868,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -878,8 +880,9 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -944,8 +947,8 @@ golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1038,6 +1041,16 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk=
google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -1092,10 +1105,10 @@ k8s.io/kms v0.30.0 h1:ZlnD/ei5lpvUlPw6eLfVvH7d8i9qZ6HwUQgydNVks8g=
k8s.io/kms v0.30.0/go.mod h1:GrMurD0qk3G4yNgGcsCEmepqf9KyyIrTXYR2lyUOJC4=
k8s.io/kube-aggregator v0.30.0 h1:+Opc0lmhRmHbNM4m3mLSsUFmK/ikMapO9rvGirX5CEM=
k8s.io/kube-aggregator v0.30.0/go.mod h1:KbZZkSSjYE6vkB2TSuZ9GBjU3ucgL7YxT8yX8wll0iQ=
k8s.io/kube-openapi v0.0.0-20240411171206-dc4e619f62f3 h1:SbdLaI6mM6ffDSJCadEaD4IkuPzepLDGlkd2xV0t1uA=
k8s.io/kube-openapi v0.0.0-20240411171206-dc4e619f62f3/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
k8s.io/utils v0.0.0-20240310230437-4693a0247e57 h1:gbqbevonBh57eILzModw6mrkbwM0gQBEuevE/AaBsHY=
k8s.io/utils v0.0.0-20240310230437-4693a0247e57/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f h1:0LQagt0gDpKqvIkAMPaRGcXawNMouPECM1+F9BVxEaM=
k8s.io/kube-openapi v0.0.0-20240430033511-f0e62f92d13f/go.mod h1:S9tOR0FxgyusSNR+MboCuiDpVWkAifZvaYI1Q2ubgro=
k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 h1:jgGTlFYnhF1PM1Ax/lAlxUPE+KfCIXHaathvJg1C3ak=
k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

View File

@@ -16,8 +16,8 @@
# See https://go.googlesource.com/go/+/dev.boringcrypto/README.boringcrypto.md
# and https://kupczynski.info/posts/fips-golang/ for details.
ARG BUILD_IMAGE=golang:1.22.2@sha256:450e3822c7a135e1463cd83e51c8e2eb03b86a02113c89424e6f0f8344bb4168
ARG BASE_IMAGE=gcr.io/distroless/static:nonroot@sha256:f41b84cda410b05cc690c2e33d1973a31c6165a2721e2b5343aab50fecb63441
ARG BUILD_IMAGE=golang:1.22.2@sha256:d5302d40dc5fbbf38ec472d1848a9d2391a13f93293a6a5b0b87c99dc0eaa6ae
ARG BASE_IMAGE=gcr.io/distroless/static:nonroot@sha256:e9ac71e2b8e279a8372741b7a0293afda17650d926900233ec3a7b2b7c22a246
# This is not currently using --platform to prepare to cross-compile because we use gcc below to build
# platform-specific GCO code. This makes multi-arch builds slow due to target platform emulation.

View File

@@ -5,7 +5,6 @@ package admissionpluginconfig
import (
"fmt"
"strings"
"github.com/pkg/errors"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
@@ -82,17 +81,16 @@ func k8sAPIServerHasValidatingAdmissionPolicyResource(discoveryClient discovery.
return false, fmt.Errorf("failed to perform k8s API discovery: %w", err)
}
// Now look at all discovered groups until we find admissionregistration.k8s.io.
wantedGroupWithSlash := fmt.Sprintf("%s/", admissionregistrationv1.GroupName)
// Now look at all discovered groups until we find version v1 of group admissionregistration.k8s.io.
for _, resourcesPerGV := range resources {
if strings.HasPrefix(resourcesPerGV.GroupVersion, wantedGroupWithSlash) {
if resourcesPerGV.GroupVersion == admissionregistrationv1.SchemeGroupVersion.String() {
// Found the group, so now look to see if it includes ValidatingAdmissionPolicy as a resource,
// which went GA in Kubernetes 1.30, and could be enabled by a feature flag in previous versions.
for _, resource := range resourcesPerGV.APIResources {
if resource.Kind == "ValidatingAdmissionPolicy" {
// Found it!
plog.Info("found ValidatingAdmissionPolicy resource on this Kubernetes cluster",
"group", resource.Group, "version", resource.Version, "kind", resource.Kind)
"groupVersion", resourcesPerGV.GroupVersion, "kind", resource.Kind)
return true, nil
}
}

View File

@@ -57,6 +57,14 @@ func TestConfigureAdmissionPlugins(t *testing.T) {
},
}
newStyleAdmissionResourcesWithValidatingAdmissionPoliciesAtOlderAPIVersion := &metav1.APIResourceList{
GroupVersion: admissionregistrationv1.SchemeGroupVersion.Group + "/v1beta1",
APIResources: []metav1.APIResource{
{Name: "validatingwebhookconfigurations", Kind: "ValidatingWebhookConfiguration"},
{Name: "validatingadmissionpolicies", Kind: "ValidatingAdmissionPolicy"},
},
}
oldStyleAdmissionResourcesWithoutValidatingAdmissionPolicies := &metav1.APIResourceList{
GroupVersion: admissionregistrationv1.SchemeGroupVersion.String(),
APIResources: []metav1.APIResource{
@@ -92,6 +100,16 @@ func TestConfigureAdmissionPlugins(t *testing.T) {
wantRegisteredPlugins: customOldStylePluginsRegistered,
wantRecommendedPluginOrder: customOldStyleRecommendedPluginOrder,
},
{
name: "when there is only an older version of ValidatingAdmissionPolicy resource, as there would be in an old Kubernetes cluster with the feature flag enabled, then we change the plugin configuration to be more like it was for old versions of Kubernetes (because the admission code wants to watch v1)",
availableAPIResources: []*metav1.APIResourceList{
coreResources,
newStyleAdmissionResourcesWithValidatingAdmissionPoliciesAtOlderAPIVersion,
appsResources,
},
wantRegisteredPlugins: customOldStylePluginsRegistered,
wantRecommendedPluginOrder: customOldStyleRecommendedPluginOrder,
},
{
name: "when there is a total error returned by discovery",
discoveryErr: errors.New("total error from API discovery client"),

View File

@@ -1,4 +1,4 @@
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Package concierge contains functionality to load/store Config's from/to
@@ -79,7 +79,6 @@ func FromPath(ctx context.Context, path string) (*Config, error) {
return nil, fmt.Errorf("validate names: %w", err)
}
plog.MaybeSetDeprecatedLogLevel(config.LogLevel, &config.Log)
if err := plog.ValidateAndSetLogLevelAndFormatGlobally(ctx, config.Log); err != nil {
return nil, fmt.Errorf("validate log level: %w", err)
}

View File

@@ -1,4 +1,4 @@
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package concierge
@@ -57,7 +57,8 @@ func TestFromPath(t *testing.T) {
namePrefix: kube-cert-agent-name-prefix-
image: kube-cert-agent-image
imagePullSecrets: [kube-cert-agent-image-pull-secret]
logLevel: debug
log:
level: debug
`),
wantConfig: &Config{
DiscoveryInfo: DiscoveryInfoSpec{
@@ -94,14 +95,13 @@ func TestFromPath(t *testing.T) {
Image: ptr.To("kube-cert-agent-image"),
ImagePullSecrets: []string{"kube-cert-agent-image-pull-secret"},
},
LogLevel: func(level plog.LogLevel) *plog.LogLevel { return &level }(plog.LevelDebug),
Log: plog.LogSpec{
Level: plog.LevelDebug,
},
},
},
{
name: "Fully filled out new log struct",
name: "fully filled out including log format",
yaml: here.Doc(`
---
discovery:
@@ -180,88 +180,6 @@ func TestFromPath(t *testing.T) {
},
},
},
{
name: "Fully filled out old log and new log struct",
yaml: here.Doc(`
---
discovery:
url: https://some.discovery/url
api:
servingCertificate:
durationSeconds: 3600
renewBeforeSeconds: 2400
apiGroupSuffix: some.suffix.com
aggregatedAPIServerPort: 12345
impersonationProxyServerPort: 4242
names:
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
credentialIssuer: pinniped-config
apiService: pinniped-api
kubeCertAgentPrefix: kube-cert-agent-prefix
impersonationLoadBalancerService: impersonationLoadBalancerService-value
impersonationClusterIPService: impersonationClusterIPService-value
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
impersonationCACertificateSecret: impersonationCACertificateSecret-value
impersonationSignerSecret: impersonationSignerSecret-value
impersonationSignerSecret: impersonationSignerSecret-value
agentServiceAccount: agentServiceAccount-value
impersonationProxyServiceAccount: impersonationProxyServiceAccount-value
impersonationProxyLegacySecret: impersonationProxyLegacySecret-value
extraName: extraName-value
labels:
myLabelKey1: myLabelValue1
myLabelKey2: myLabelValue2
kubeCertAgent:
namePrefix: kube-cert-agent-name-prefix-
image: kube-cert-agent-image
imagePullSecrets: [kube-cert-agent-image-pull-secret]
logLevel: debug
log:
level: all
format: json
`),
wantConfig: &Config{
DiscoveryInfo: DiscoveryInfoSpec{
URL: ptr.To("https://some.discovery/url"),
},
APIConfig: APIConfigSpec{
ServingCertificateConfig: ServingCertificateConfigSpec{
DurationSeconds: ptr.To[int64](3600),
RenewBeforeSeconds: ptr.To[int64](2400),
},
},
APIGroupSuffix: ptr.To("some.suffix.com"),
AggregatedAPIServerPort: ptr.To[int64](12345),
ImpersonationProxyServerPort: ptr.To[int64](4242),
NamesConfig: NamesConfigSpec{
ServingCertificateSecret: "pinniped-concierge-api-tls-serving-certificate",
CredentialIssuer: "pinniped-config",
APIService: "pinniped-api",
ImpersonationLoadBalancerService: "impersonationLoadBalancerService-value",
ImpersonationClusterIPService: "impersonationClusterIPService-value",
ImpersonationTLSCertificateSecret: "impersonationTLSCertificateSecret-value",
ImpersonationCACertificateSecret: "impersonationCACertificateSecret-value",
ImpersonationSignerSecret: "impersonationSignerSecret-value",
AgentServiceAccount: "agentServiceAccount-value",
ImpersonationProxyServiceAccount: "impersonationProxyServiceAccount-value",
ImpersonationProxyLegacySecret: "impersonationProxyLegacySecret-value",
},
Labels: map[string]string{
"myLabelKey1": "myLabelValue1",
"myLabelKey2": "myLabelValue2",
},
KubeCertAgentConfig: KubeCertAgentSpec{
NamePrefix: ptr.To("kube-cert-agent-name-prefix-"),
Image: ptr.To("kube-cert-agent-image"),
ImagePullSecrets: []string{"kube-cert-agent-image-pull-secret"},
},
LogLevel: func(level plog.LogLevel) *plog.LogLevel { return &level }(plog.LevelDebug),
Log: plog.LogSpec{
Level: plog.LevelDebug,
Format: plog.FormatJSON,
},
},
},
{
name: "invalid log format",
yaml: here.Doc(`
@@ -281,7 +199,28 @@ func TestFromPath(t *testing.T) {
level: all
format: snorlax
`),
wantError: "decode yaml: error unmarshaling JSON: while decoding JSON: invalid log format, valid choices are the empty string, json and text",
wantError: "decode yaml: error unmarshaling JSON: while decoding JSON: invalid log format, valid choices are the empty string or 'json'",
},
{
name: "cli is a bad log format when configured by the user",
yaml: here.Doc(`
---
names:
servingCertificateSecret: pinniped-concierge-api-tls-serving-certificate
credentialIssuer: pinniped-config
apiService: pinniped-api
impersonationLoadBalancerService: impersonationLoadBalancerService-value
impersonationClusterIPService: impersonationClusterIPService-value
impersonationTLSCertificateSecret: impersonationTLSCertificateSecret-value
impersonationCACertificateSecret: impersonationCACertificateSecret-value
impersonationSignerSecret: impersonationSignerSecret-value
agentServiceAccount: agentServiceAccount-value
impersonationProxyServiceAccount: impersonationProxyServiceAccount-value
log:
level: all
format: cli
`),
wantError: "decode yaml: error unmarshaling JSON: while decoding JSON: invalid log format, valid choices are the empty string or 'json'",
},
{
name: "When only the required fields are present, causes other fields to be defaulted",

View File

@@ -1,4 +1,4 @@
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package concierge
@@ -15,9 +15,7 @@ type Config struct {
NamesConfig NamesConfigSpec `json:"names"`
KubeCertAgentConfig KubeCertAgentSpec `json:"kubeCertAgent"`
Labels map[string]string `json:"labels"`
// Deprecated: use log.level instead
LogLevel *plog.LogLevel `json:"logLevel"`
Log plog.LogSpec `json:"log"`
Log plog.LogSpec `json:"log"`
}
// DiscoveryInfoSpec contains configuration knobs specific to

View File

@@ -1,4 +1,4 @@
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
// Package supervisor contains functionality to load/store Config's from/to
@@ -66,7 +66,6 @@ func FromPath(ctx context.Context, path string) (*Config, error) {
return nil, fmt.Errorf("validate names: %w", err)
}
plog.MaybeSetDeprecatedLogLevel(config.LogLevel, &config.Log)
if err := plog.ValidateAndSetLogLevelAndFormatGlobally(ctx, config.Log); err != nil {
return nil, fmt.Errorf("validate log level: %w", err)
}
@@ -90,7 +89,7 @@ func FromPath(ctx context.Context, path string) (*Config, error) {
if err := validateEndpoint(*config.Endpoints.HTTP); err != nil {
return nil, fmt.Errorf("validate http endpoint: %w", err)
}
if err := validateAdditionalHTTPEndpointRequirements(*config.Endpoints.HTTP, config.AllowExternalHTTP); err != nil {
if err := validateAdditionalHTTPEndpointRequirements(*config.Endpoints.HTTP); err != nil {
return nil, fmt.Errorf("validate http endpoint: %w", err)
}
if err := validateAtLeastOneEnabledEndpoint(*config.Endpoints.HTTPS, *config.Endpoints.HTTP); err != nil {
@@ -151,16 +150,8 @@ func validateEndpoint(endpoint Endpoint) error {
}
}
func validateAdditionalHTTPEndpointRequirements(endpoint Endpoint, allowExternalHTTP stringOrBoolAsBool) error {
func validateAdditionalHTTPEndpointRequirements(endpoint Endpoint) error {
if endpoint.Network == NetworkTCP && !addrIsOnlyOnLoopback(endpoint.Address) {
if allowExternalHTTP {
// Log that the validation should have been triggered.
plog.Warning("Listening on non-loopback interfaces for the HTTP port is deprecated and will be removed " +
"in a future release. Your current configuration would not be allowed in that future release. " +
"Please see comments in deploy/supervisor/values.yaml and review your settings.")
// Skip enforcement of the validation.
return nil
}
return fmt.Errorf(
"http listener address %q for %q network may only bind to loopback interfaces",
endpoint.Address,

View File

@@ -1,4 +1,4 @@
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package supervisor
@@ -25,54 +25,6 @@ func TestFromPath(t *testing.T) {
}{
{
name: "Happy",
yaml: here.Doc(`
---
apiGroupSuffix: some.suffix.com
labels:
myLabelKey1: myLabelValue1
myLabelKey2: myLabelValue2
names:
defaultTLSCertificateSecret: my-secret-name
endpoints:
https:
network: unix
address: :1234
http:
network: tcp
address: 127.0.0.1:1234
insecureAcceptExternalUnencryptedHttpRequests: false
logLevel: trace
aggregatedAPIServerPort: 12345
`),
wantConfig: &Config{
APIGroupSuffix: ptr.To("some.suffix.com"),
Labels: map[string]string{
"myLabelKey1": "myLabelValue1",
"myLabelKey2": "myLabelValue2",
},
NamesConfig: NamesConfigSpec{
DefaultTLSCertificateSecret: "my-secret-name",
},
Endpoints: &Endpoints{
HTTPS: &Endpoint{
Network: "unix",
Address: ":1234",
},
HTTP: &Endpoint{
Network: "tcp",
Address: "127.0.0.1:1234",
},
},
AllowExternalHTTP: false,
LogLevel: func(level plog.LogLevel) *plog.LogLevel { return &level }(plog.LevelTrace),
Log: plog.LogSpec{
Level: plog.LevelTrace,
},
AggregatedAPIServerPort: ptr.To[int64](12345),
},
},
{
name: "Happy with new log field",
yaml: here.Doc(`
---
apiGroupSuffix: some.suffix.com
@@ -91,7 +43,7 @@ func TestFromPath(t *testing.T) {
insecureAcceptExternalUnencryptedHttpRequests: false
log:
level: info
format: text
format: json
aggregatedAPIServerPort: 12345
`),
wantConfig: &Config{
@@ -113,67 +65,15 @@ func TestFromPath(t *testing.T) {
Address: "127.0.0.1:1234",
},
},
AllowExternalHTTP: false,
Log: plog.LogSpec{
Level: plog.LevelInfo,
Format: plog.FormatText,
Format: plog.FormatJSON,
},
AggregatedAPIServerPort: ptr.To[int64](12345),
},
},
{
name: "Happy with old and new log field",
yaml: here.Doc(`
---
apiGroupSuffix: some.suffix.com
labels:
myLabelKey1: myLabelValue1
myLabelKey2: myLabelValue2
names:
defaultTLSCertificateSecret: my-secret-name
endpoints:
https:
network: unix
address: :1234
http:
network: tcp
address: 127.0.0.1:1234
insecureAcceptExternalUnencryptedHttpRequests: false
logLevel: trace
log:
level: info
format: text
`),
wantConfig: &Config{
APIGroupSuffix: ptr.To("some.suffix.com"),
Labels: map[string]string{
"myLabelKey1": "myLabelValue1",
"myLabelKey2": "myLabelValue2",
},
NamesConfig: NamesConfigSpec{
DefaultTLSCertificateSecret: "my-secret-name",
},
Endpoints: &Endpoints{
HTTPS: &Endpoint{
Network: "unix",
Address: ":1234",
},
HTTP: &Endpoint{
Network: "tcp",
Address: "127.0.0.1:1234",
},
},
AllowExternalHTTP: false,
LogLevel: func(level plog.LogLevel) *plog.LogLevel { return &level }(plog.LevelTrace),
Log: plog.LogSpec{
Level: plog.LevelTrace,
Format: plog.FormatText,
},
AggregatedAPIServerPort: ptr.To[int64](10250),
},
},
{
name: "bad log format",
name: "cli is a bad log format when configured by the user",
yaml: here.Doc(`
---
names:
@@ -182,7 +82,7 @@ func TestFromPath(t *testing.T) {
level: info
format: cli
`),
wantError: "decode yaml: error unmarshaling JSON: while decoding JSON: invalid log format, valid choices are the empty string, json and text",
wantError: "decode yaml: error unmarshaling JSON: while decoding JSON: invalid log format, valid choices are the empty string or 'json'",
},
{
name: "When only the required fields are present, causes other fields to be defaulted",
@@ -206,7 +106,6 @@ func TestFromPath(t *testing.T) {
Network: "disabled",
},
},
AllowExternalHTTP: false,
AggregatedAPIServerPort: ptr.To[int64](10250),
},
},
@@ -268,7 +167,7 @@ func TestFromPath(t *testing.T) {
wantError: `validate http endpoint: http listener address ":8080" for "tcp" network may only bind to loopback interfaces`,
},
{
name: "http endpoint uses tcp but binds to more than only loopback interfaces with insecureAcceptExternalUnencryptedHttpRequests set to boolean false",
name: "http endpoint uses tcp but binds to more than only loopback interfaces",
yaml: here.Doc(`
---
names:
@@ -279,100 +178,9 @@ func TestFromPath(t *testing.T) {
http:
network: tcp
address: :8080
insecureAcceptExternalUnencryptedHttpRequests: false
`),
wantError: `validate http endpoint: http listener address ":8080" for "tcp" network may only bind to loopback interfaces`,
},
{
name: "http endpoint uses tcp but binds to more than only loopback interfaces with insecureAcceptExternalUnencryptedHttpRequests set to unsupported value",
yaml: here.Doc(`
---
names:
defaultTLSCertificateSecret: my-secret-name
insecureAcceptExternalUnencryptedHttpRequests: "garbage" # this will be treated as the default, which is false
`),
wantError: `decode yaml: error unmarshaling JSON: while decoding JSON: invalid value for boolean`,
},
{
name: "http endpoint uses tcp but binds to more than only loopback interfaces with insecureAcceptExternalUnencryptedHttpRequests set to string false",
yaml: here.Doc(`
---
names:
defaultTLSCertificateSecret: my-secret-name
endpoints:
https:
network: disabled
http:
network: tcp
address: :8080
insecureAcceptExternalUnencryptedHttpRequests: "false"
`),
wantError: `validate http endpoint: http listener address ":8080" for "tcp" network may only bind to loopback interfaces`,
},
{
name: "http endpoint uses tcp but binds to more than only loopback interfaces with insecureAcceptExternalUnencryptedHttpRequests set to boolean true",
yaml: here.Doc(`
---
names:
defaultTLSCertificateSecret: my-secret-name
endpoints:
http:
network: tcp
address: :1234
insecureAcceptExternalUnencryptedHttpRequests: true
`),
wantConfig: &Config{
APIGroupSuffix: ptr.To("pinniped.dev"),
Labels: map[string]string{},
NamesConfig: NamesConfigSpec{
DefaultTLSCertificateSecret: "my-secret-name",
},
Endpoints: &Endpoints{
HTTPS: &Endpoint{
Network: "tcp",
Address: ":8443",
},
HTTP: &Endpoint{
Network: "tcp",
Address: ":1234",
},
},
AllowExternalHTTP: true,
AggregatedAPIServerPort: ptr.To[int64](10250),
},
},
{
name: "http endpoint uses tcp but binds to more than only loopback interfaces with insecureAcceptExternalUnencryptedHttpRequests set to string true",
yaml: here.Doc(`
---
names:
defaultTLSCertificateSecret: my-secret-name
endpoints:
http:
network: tcp
address: :1234
insecureAcceptExternalUnencryptedHttpRequests: "true"
`),
wantConfig: &Config{
APIGroupSuffix: ptr.To("pinniped.dev"),
Labels: map[string]string{},
NamesConfig: NamesConfigSpec{
DefaultTLSCertificateSecret: "my-secret-name",
},
Endpoints: &Endpoints{
HTTPS: &Endpoint{
Network: "tcp",
Address: ":8443",
},
HTTP: &Endpoint{
Network: "tcp",
Address: ":1234",
},
},
AllowExternalHTTP: true,
AggregatedAPIServerPort: ptr.To[int64](10250),
},
},
{
name: "endpoint disabled with non-empty address",
yaml: here.Doc(`

View File

@@ -1,25 +1,20 @@
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package supervisor
import (
"errors"
"go.pinniped.dev/internal/plog"
)
// Config contains knobs to setup an instance of the Pinniped Supervisor.
type Config struct {
APIGroupSuffix *string `json:"apiGroupSuffix,omitempty"`
Labels map[string]string `json:"labels"`
NamesConfig NamesConfigSpec `json:"names"`
// Deprecated: use log.level instead
LogLevel *plog.LogLevel `json:"logLevel"`
Log plog.LogSpec `json:"log"`
Endpoints *Endpoints `json:"endpoints"`
AllowExternalHTTP stringOrBoolAsBool `json:"insecureAcceptExternalUnencryptedHttpRequests"`
AggregatedAPIServerPort *int64 `json:"aggregatedAPIServerPort"`
APIGroupSuffix *string `json:"apiGroupSuffix,omitempty"`
Labels map[string]string `json:"labels"`
NamesConfig NamesConfigSpec `json:"names"`
Log plog.LogSpec `json:"log"`
Endpoints *Endpoints `json:"endpoints"`
AggregatedAPIServerPort *int64 `json:"aggregatedAPIServerPort"`
}
// NamesConfigSpec configures the names of some Kubernetes resources for the Supervisor.
@@ -37,17 +32,3 @@ type Endpoint struct {
Network string `json:"network"`
Address string `json:"address"`
}
type stringOrBoolAsBool bool
func (sb *stringOrBoolAsBool) UnmarshalJSON(b []byte) error {
switch string(b) {
case "true", `"true"`:
*sb = true
case "false", `"false"`:
*sb = false
default:
return errors.New("invalid value for boolean")
}
return nil
}

View File

@@ -428,7 +428,13 @@ func TestFuzzAndJSONNewValidEmptyAuthorizeCodeSession(t *testing.T) {
// cause those old session Secrets to be discarded upon read after an upgrade.
// Note that when you change the storage version, you will also need to change it in the JSON content of the
// expected value for this assertion.
require.JSONEq(t, ExpectedAuthorizeCodeSessionJSONFromFuzzing, authorizeCodeSessionJSONFromFuzzing, "actual:\n%s", authorizeCodeSessionJSONFromFuzzing)
require.JSONEq(t,
ExpectedAuthorizeCodeSessionJSONFromFuzzing,
authorizeCodeSessionJSONFromFuzzing,
"actual:\n%s\n\n(NOTICE: This test may fail when storage structure is updated. "+
"Be sure to update relevant version variables (authorizeCodeStorageVersion, oidcStorageVersion, pkceStorageVersion, "+
"refreshTokenStorageVersion, accessTokenStorageVersion) to a new value and leave a comment documenting the change. "+
"Updating the version ensures new secret generation, therefore smooth upgrades of Pinniped.)", authorizeCodeSessionJSONFromFuzzing)
}
func TestReadFromSecret(t *testing.T) {

View File

@@ -1,4 +1,4 @@
// Copyright 2020-2022 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package plog
@@ -22,8 +22,6 @@ func (l *LogFormat) UnmarshalJSON(b []byte) error {
switch string(b) {
case `""`, `"json"`:
*l = FormatJSON
case `"text"`:
*l = FormatText
// there is no "cli" case because it is not a supported option via our config
default:
return errInvalidLogFormat
@@ -33,11 +31,10 @@ func (l *LogFormat) UnmarshalJSON(b []byte) error {
const (
FormatJSON LogFormat = "json"
FormatText LogFormat = "text"
FormatCLI LogFormat = "cli" // only used by the pinniped CLI and not the server components
errInvalidLogLevel = constable.Error("invalid log level, valid choices are the empty string, info, debug, trace and all")
errInvalidLogFormat = constable.Error("invalid log format, valid choices are the empty string, json and text")
errInvalidLogFormat = constable.Error("invalid log format, valid choices are the empty string or 'json'")
)
var _ json.Unmarshaler = func() *LogFormat {
@@ -50,13 +47,6 @@ type LogSpec struct {
Format LogFormat `json:"format,omitempty"`
}
func MaybeSetDeprecatedLogLevel(level *LogLevel, log *LogSpec) {
if level != nil {
Warning("logLevel is deprecated, set log.level instead")
log.Level = *level
}
}
func ValidateAndSetLogLevelAndFormatGlobally(ctx context.Context, spec LogSpec) error {
klogLevel := klogLevelForPlogLevel(spec.Level)
if klogLevel < 0 {
@@ -75,8 +65,6 @@ func ValidateAndSetLogLevelAndFormatGlobally(ctx context.Context, spec LogSpec)
encoding = "json"
case FormatCLI:
encoding = "console"
case FormatText:
encoding = "text"
default:
return errInvalidLogFormat
}
@@ -88,12 +76,8 @@ func ValidateAndSetLogLevelAndFormatGlobally(ctx context.Context, spec LogSpec)
setGlobalLoggers(log, flush)
//nolint:exhaustive // the switch above is exhaustive for format already
switch spec.Format {
case FormatCLI:
if spec.Format == FormatCLI {
return nil // do not spawn go routines on the CLI to allow the CLI to call this more than once
case FormatText:
Warning("setting log.format to 'text' is deprecated - this option will be removed in a future release")
}
// do spawn go routines on the server

View File

@@ -1,4 +1,4 @@
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2024 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package plog
@@ -101,7 +101,7 @@ func TestFormat(t *testing.T) {
"timestamp": "2022-11-21T23:37:26.953313Z",
"caller": "%s/config_test.go:%d$plog.TestFormat.func1",
"message": "something happened",
"error": "invalid log format, valid choices are the empty string, json and text",
"error": "invalid log format, valid choices are the empty string or 'json'",
"an": "item"
}`, wd, getLineNumberOfCaller()-11), scanner.Text())
@@ -148,7 +148,7 @@ testing.tRunner
DebugErr("something happened", errInvalidLogFormat, "an", "item")
require.True(t, scanner.Scan())
require.NoError(t, scanner.Err())
require.Equal(t, fmt.Sprintf(nowStr+` plog/config_test.go:%d something happened {"error": "invalid log format, valid choices are the empty string, json and text", "an": "item"}`,
require.Equal(t, fmt.Sprintf(nowStr+` plog/config_test.go:%d something happened {"error": "invalid log format, valid choices are the empty string or 'json'", "an": "item"}`,
getLineNumberOfCaller()-4), scanner.Text())
Logr().WithName("burrito").Error(errInvalidLogLevel, "wee", "a", "b", "slightly less than a year", 363*24*time.Hour, "slightly more than 2 years", 2*367*24*time.Hour)
@@ -157,74 +157,6 @@ testing.tRunner
require.Equal(t, fmt.Sprintf(nowStr+` burrito plog/config_test.go:%d wee {"a": "b", "slightly less than a year": "363d", "slightly more than 2 years": "2y4d", "error": "invalid log level, valid choices are the empty string, info, debug, trace and all"}`,
getLineNumberOfCaller()-4), scanner.Text())
old := New().WithName("created before mode change").WithValues("is", "old")
err = ValidateAndSetLogLevelAndFormatGlobally(ctx, LogSpec{Level: LevelDebug, Format: FormatText})
require.NoError(t, err)
pid := os.Getpid()
// check for the deprecation warning
require.True(t, scanner.Scan())
require.NoError(t, scanner.Err())
require.Equal(t, fmt.Sprintf(`I1121 23:37:26.953313%8d config.go:96] "setting log.format to 'text' is deprecated - this option will be removed in a future release" warning=true`,
pid), scanner.Text())
Debug("what is happening", "does klog", "work?")
require.True(t, scanner.Scan())
require.NoError(t, scanner.Err())
require.Equal(t, fmt.Sprintf(`I1121 23:37:26.953313%8d config_test.go:%d] "what is happening" does klog="work?"`,
pid, getLineNumberOfCaller()-4), scanner.Text())
Logr().WithName("panda").V(KlogLevelDebug).Info("are the best", "yes?", "yes.")
require.True(t, scanner.Scan())
require.NoError(t, scanner.Err())
require.Equal(t, fmt.Sprintf(`I1121 23:37:26.953313%8d config_test.go:%d] "are the best" logger="panda" yes?="yes."`,
pid, getLineNumberOfCaller()-4), scanner.Text())
New().WithName("hi").WithName("there").WithValues("a", 1, "b", 2).Always("do it")
require.True(t, scanner.Scan())
require.NoError(t, scanner.Err())
require.Equal(t, fmt.Sprintf(`I1121 23:37:26.953313%8d config_test.go:%d] "do it" logger="hi.there" a=1 b=2`,
pid, getLineNumberOfCaller()-4), scanner.Text())
l := WithValues("x", 33, "z", 22)
l.Debug("what to do")
l.Debug("and why")
require.True(t, scanner.Scan())
require.NoError(t, scanner.Err())
require.Equal(t, fmt.Sprintf(`I1121 23:37:26.953313%8d config_test.go:%d] "what to do" x=33 z=22`,
pid, getLineNumberOfCaller()-5), scanner.Text())
require.True(t, scanner.Scan())
require.NoError(t, scanner.Err())
require.Equal(t, fmt.Sprintf(`I1121 23:37:26.953313%8d config_test.go:%d] "and why" x=33 z=22`,
pid, getLineNumberOfCaller()-8), scanner.Text())
old.Always("should be klog text format", "for", "sure")
require.True(t, scanner.Scan())
require.NoError(t, scanner.Err())
require.Equal(t, fmt.Sprintf(`I1121 23:37:26.953313%8d config_test.go:%d] "should be klog text format" logger="created before mode change" is="old" for="sure"`,
pid, getLineNumberOfCaller()-4), scanner.Text())
// make sure child loggers do not share state
old1 := old.WithValues("i am", "old1")
old2 := old.WithName("old2")
old1.Warning("warn")
old2.Info("info")
require.True(t, scanner.Scan())
require.NoError(t, scanner.Err())
require.Equal(t, fmt.Sprintf(`I1121 23:37:26.953313%8d config_test.go:%d] "warn" logger="created before mode change" is="old" i am="old1" warning=true`,
pid, getLineNumberOfCaller()-5), scanner.Text())
require.True(t, scanner.Scan())
require.NoError(t, scanner.Err())
require.Equal(t, fmt.Sprintf(`I1121 23:37:26.953313%8d config_test.go:%d] "info" logger="created before mode change.old2" is="old"`,
pid, getLineNumberOfCaller()-8), scanner.Text())
Trace("should not be logged", "for", "sure")
require.Empty(t, buf.String())
Logr().V(klogLevelAll).Info("also should not be logged", "open", "close")
require.Empty(t, buf.String())
require.False(t, scanner.Scan())
require.NoError(t, scanner.Err())
require.Empty(t, scanner.Text())

View File

@@ -1,4 +1,4 @@
// Copyright 2022-2023 the Pinniped contributors. All Rights Reserved.
// Copyright 2022-2024 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package clientsecretrequest
@@ -33,6 +33,7 @@ import (
supervisorfake "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/fake"
"go.pinniped.dev/internal/oidcclientsecretstorage"
"go.pinniped.dev/internal/plog"
"go.pinniped.dev/internal/testutil"
)
func TestNew(t *testing.T) {
@@ -1563,8 +1564,12 @@ func TestCreate(t *testing.T) {
var log bytes.Buffer
logger := plog.TestZapr(t, &log)
klog.SetLogger(logger)
originalKLogLevel := testutil.GetGlobalKlogLevel()
// trace.Log() utility will only log at level 2 or above, so set that for this test.
testutil.SetGlobalKlogLevel(t, 2) //nolint:staticcheck // old test of code using trace.Log()
t.Cleanup(func() {
klog.ClearLogger()
testutil.SetGlobalKlogLevel(t, originalKLogLevel) //nolint:staticcheck // old test of code using trace.Log()
})
kubeClient := kubefake.NewSimpleClientset()

View File

@@ -68,16 +68,21 @@ func TestCreate(t *testing.T) {
var r *require.Assertions
var ctrl *gomock.Controller
var logger *testutil.TranscriptLogger
var originalKLogLevel klog.Level
it.Before(func() {
r = require.New(t)
ctrl = gomock.NewController(t)
logger = testutil.NewTranscriptLogger(t) //nolint:staticcheck // old test with lots of log statements
klog.SetLogger(logr.New(logger)) // this is unfortunately a global logger, so can't run these tests in parallel :(
originalKLogLevel = testutil.GetGlobalKlogLevel()
// trace.Log() utility will only log at level 2 or above, so set that for this test.
testutil.SetGlobalKlogLevel(t, 2) //nolint:staticcheck // old test of code using trace.Log()
})
it.After(func() {
klog.ClearLogger()
testutil.SetGlobalKlogLevel(t, originalKLogLevel) //nolint:staticcheck // old test of code using trace.Log()
ctrl.Finish()
})

View File

@@ -0,0 +1,32 @@
// Copyright 2024 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package testutil
import (
"strconv"
"testing"
"github.com/stretchr/testify/require"
"k8s.io/component-base/logs"
"k8s.io/klog/v2"
)
// Deprecated: This is meant for old tests only.
func SetGlobalKlogLevel(t *testing.T, l klog.Level) {
t.Helper()
_, err := logs.GlogSetter(strconv.Itoa(int(l)))
require.NoError(t, err)
}
func GetGlobalKlogLevel() klog.Level {
// hack around klog not exposing a Get method
for i := klog.Level(0); i < 256; i++ {
if klog.V(i).Enabled() {
continue
}
return i - 1
}
return -1
}

View File

@@ -61,17 +61,8 @@ It is recommended that the traffic to these endpoints should be encrypted via TL
Supervisor pods, even when crossing boundaries that are entirely inside the Kubernetes cluster.
The credentials and tokens that are handled by these endpoints are too sensitive to transmit without encryption.
In previous versions of the Supervisor app, there were both HTTP and HTTPS ports available for use by default.
These ports each host all the Supervisor's endpoints. Unfortunately, this has caused some confusion in the community
and some blog posts have been written which demonstrate using the HTTP port in such a way that a portion of the traffic's
path is unencrypted. Newer versions of the Supervisor disable the HTTP port by default to make it more clear that
the Supervisor app is not intended to receive non-TLS HTTP traffic from outside the Pod. Furthermore, in these newer versions,
when the HTTP listener is configured to be enabled it may only listen on loopback interfaces for traffic from within its own pod.
To aid in transition for impacted users, the old behavior of allowing the HTTP listener to receive traffic from
outside the pod may be re-enabled using the
`deprecated_insecure_accept_external_unencrypted_http_requests` value in
[values.yaml](https://github.com/vmware-tanzu/pinniped/blob/main/deploy/supervisor/values.yaml),
until that setting is removed in a future release.
The Supervisor only listens on an HTTPS port by default. Incoming traffic must use TLS. The only exception is for
an advanced configuration style using a service mesh to deliver traffic into the Supervisor (discussed below).
Because there are many ways to expose TLS services from a Kubernetes cluster, the Supervisor app leaves this up to the user.
Some common approaches are: