Compare commits

...

23 Commits

Author SHA1 Message Date
Ryan Richard
39d35ceca0 Merge pull request #2883 from vmware/pinny/update-version-and-cli-docs
Some checks failed
CodeQL / Analyze (go) (push) Failing after 1m44s
CodeQL / Analyze (javascript) (push) Failing after 1m8s
Update version and CLI docs on website
2026-01-30 12:32:09 -08:00
Pinny
da86068f4e Update version and CLI docs on website 2026-01-30 20:30:56 +00:00
Ryan Richard
eef4934775 Merge pull request #2873 from vmware/pinny/bump-deps
Some checks failed
CodeQL / Analyze (go) (push) Failing after 1m57s
CodeQL / Analyze (javascript) (push) Failing after 1m12s
Bump dependencies
2026-01-29 11:03:38 -08:00
Pinny
a72c51f823 Bump dependencies 2026-01-29 14:06:00 +00:00
Ryan Richard
6797d8622a Merge pull request #2872 from vmware/rr/update-codegen-versions
Some checks failed
CodeQL / Analyze (go) (push) Failing after 2m8s
CodeQL / Analyze (javascript) (push) Failing after 1m7s
update k8s patch versions for generated code
2026-01-28 14:59:06 -08:00
Ryan Richard
beeb6dad6e Merge pull request #2837 from vmware/pinny/bump-deps
Some checks failed
CodeQL / Analyze (go) (push) Failing after 1m47s
CodeQL / Analyze (javascript) (push) Failing after 1m6s
Bump dependencies
2026-01-27 13:50:05 -08:00
Ryan Richard
5f6bbc691b update k8s patch versions for generated code 2026-01-27 12:12:48 -08:00
Pinny
13cc7b147d Bump dependencies 2026-01-27 19:05:42 +00:00
Ryan Richard
cc80df6107 Merge pull request #2869 from vmware/rr/partial_anon_auth
support partial anonymous authentication in the impersonation proxy
2026-01-27 11:03:14 -08:00
Ryan Richard
736e2472c6 integration tests decide if cluster supports anon auth more dynamically 2026-01-26 16:04:17 -08:00
Ryan Richard
0f0f3997a0 support partial enablement of anonymous authentication in impersonator 2026-01-23 13:11:29 -08:00
Ryan Richard
de32fdc304 update-copyright-year.sh does not exit 1 on success so CI can call it
Some checks failed
CodeQL / Analyze (go) (push) Failing after 2m0s
CodeQL / Analyze (javascript) (push) Failing after 1m24s
2026-01-21 12:21:56 -08:00
Ryan Richard
ec334d1175 update-majors.sh and update-copyright-year.sh can use linux sed flags 2026-01-21 12:10:39 -08:00
Ryan Richard
5d9b7a3346 update update-majors.sh to use linux flag to "find" for use in CI 2026-01-21 11:33:14 -08:00
Ryan Richard
6577c523de update update-majors.sh for use in CI 2026-01-21 10:49:51 -08:00
Ryan Richard
a47c5bf5fe Merge pull request #2838 from vmware/dependabot/go_modules/hack/update-go-mod/golang.org/x/mod-0.32.0
Bump golang.org/x/mod from 0.29.0 to 0.32.0 in /hack/update-go-mod
2026-01-21 10:31:26 -08:00
dependabot[bot]
43fe4a886e Bump golang.org/x/mod from 0.29.0 to 0.32.0 in /hack/update-go-mod
Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.29.0 to 0.32.0.
- [Commits](https://github.com/golang/mod/compare/v0.29.0...v0.32.0)

---
updated-dependencies:
- dependency-name: golang.org/x/mod
  dependency-version: 0.32.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-12 01:54:58 +00:00
Ryan Richard
174b3026c7 Merge pull request #2831 from vmware/pinny/bump-deps
Some checks failed
CodeQL / Analyze (go) (push) Failing after 2m9s
CodeQL / Analyze (javascript) (push) Failing after 1m15s
Bump dependencies
2026-01-06 11:59:37 -08:00
Pinny
e009d22900 Bump dependencies 2026-01-06 14:08:37 +00:00
Ryan Richard
4b7fbc144e Merge pull request #2827 from vmware/pinny/bump-deps
Some checks failed
CodeQL / Analyze (go) (push) Failing after 2m31s
CodeQL / Analyze (javascript) (push) Failing after 1m9s
Bump dependencies
2026-01-05 11:24:49 -08:00
Pinny
98621c76b5 Bump dependencies 2026-01-05 14:01:53 +00:00
Ryan Richard
6d8aed7f40 Merge pull request #2823 from vmware/pinny/update-version-and-cli-docs
Some checks failed
CodeQL / Analyze (go) (push) Failing after 1m45s
CodeQL / Analyze (javascript) (push) Failing after 1m17s
Update version and CLI docs on website
2025-12-24 09:36:53 -08:00
Pinny
3031a070d1 Update version and CLI docs on website 2025-12-24 01:28:35 +00:00
36 changed files with 658 additions and 237 deletions

View File

@@ -1,10 +1,10 @@
# syntax=docker/dockerfile:1
# Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
# Copyright 2020-2026 the Pinniped contributors. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
ARG BUILD_IMAGE=golang:1.25.5@sha256:36b4f45d2874905b9e8573b783292629bcb346d0a70d8d7150b6df545234818f
ARG BASE_IMAGE=gcr.io/distroless/static:nonroot@sha256:2b7c93f6d6648c11f0e80a48558c8f77885eb0445213b8e69a6a0d7c89fc6ae4
ARG BUILD_IMAGE=golang:1.25.6@sha256:ce63a16e0f7063787ebb4eb28e72d477b00b4726f79874b3205a965ffd797ab2
ARG BASE_IMAGE=gcr.io/distroless/static:nonroot@sha256:cba10d7abd3e203428e86f5b2d7fd5eb7d8987c387864ae4996cf97191b33764
# 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

@@ -4,8 +4,8 @@ module go.pinniped.dev/generated/1.32/apis
go 1.23.0
require (
k8s.io/api v0.32.10
k8s.io/apimachinery v0.32.10
k8s.io/api v0.32.11
k8s.io/apimachinery v0.32.11
)
require (

View File

@@ -79,10 +79,10 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.32.10 h1:ocp4turNfa1V40TuBW/LuA17TeXG9g/GI2ebg0KxBNk=
k8s.io/api v0.32.10/go.mod h1:AsMsc4b6TuampYqgMEGSv0HBFpRS4BlKTXAVCAa7oF4=
k8s.io/apimachinery v0.32.10 h1:SAg2kUPLYRcBJQj66oniP1BnXSqw+l1GvJFsJlBmVvQ=
k8s.io/apimachinery v0.32.10/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
k8s.io/api v0.32.11 h1:0MnAbAc3GDHJcMyoWufyNTOiAMu46SnOg+pGaNdL6mc=
k8s.io/api v0.32.11/go.mod h1:FOEM0Zd1QYD4cqXI9CvJz/tmqMcxFQv222KNOZtghO0=
k8s.io/apimachinery v0.32.11 h1:QCjwmozCmod1kK+lvLGKlq4AXSw0ncCD5OSI6JyOrE8=
k8s.io/apimachinery v0.32.11/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=

View File

@@ -7,9 +7,9 @@ replace go.pinniped.dev/generated/1.32/apis => ../apis
require (
go.pinniped.dev/generated/1.32/apis v0.0.0
k8s.io/api v0.32.10
k8s.io/apimachinery v0.32.10
k8s.io/client-go v0.32.10
k8s.io/api v0.32.11
k8s.io/apimachinery v0.32.11
k8s.io/client-go v0.32.11
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f
)

View File

@@ -134,12 +134,12 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.32.10 h1:ocp4turNfa1V40TuBW/LuA17TeXG9g/GI2ebg0KxBNk=
k8s.io/api v0.32.10/go.mod h1:AsMsc4b6TuampYqgMEGSv0HBFpRS4BlKTXAVCAa7oF4=
k8s.io/apimachinery v0.32.10 h1:SAg2kUPLYRcBJQj66oniP1BnXSqw+l1GvJFsJlBmVvQ=
k8s.io/apimachinery v0.32.10/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
k8s.io/client-go v0.32.10 h1:MFmIjsKtcnn7mStjrJG1ZW2WzLsKKn6ZtL9hHM/W0xU=
k8s.io/client-go v0.32.10/go.mod h1:qJy/Ws3zSwnu/nD75D+/of1uxbwWHxrYT5P3FuobVLI=
k8s.io/api v0.32.11 h1:0MnAbAc3GDHJcMyoWufyNTOiAMu46SnOg+pGaNdL6mc=
k8s.io/api v0.32.11/go.mod h1:FOEM0Zd1QYD4cqXI9CvJz/tmqMcxFQv222KNOZtghO0=
k8s.io/apimachinery v0.32.11 h1:QCjwmozCmod1kK+lvLGKlq4AXSw0ncCD5OSI6JyOrE8=
k8s.io/apimachinery v0.32.11/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
k8s.io/client-go v0.32.11 h1:HHcSUf+wuiQ+2kpM0CbzhXQ3mhHOmnzw6ctGbLre+ho=
k8s.io/client-go v0.32.11/go.mod h1:8pdqbF5/hF++ZEK1I7poxNH4CTlFNkHN48h4si+qDqQ=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y=

View File

@@ -4,8 +4,8 @@ module go.pinniped.dev/generated/1.33/apis
go 1.24.0
require (
k8s.io/api v0.33.6
k8s.io/apimachinery v0.33.6
k8s.io/api v0.33.7
k8s.io/apimachinery v0.33.7
)
require (

View File

@@ -75,10 +75,10 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.33.6 h1:9O22ZqwT6CkQ3iboVpvTR5BEWuT3Xm6/8NX6MOLmc38=
k8s.io/api v0.33.6/go.mod h1:bdon4pRFmRmdsFyltGIoCaPqutN7y//OQ4srD0uy9X0=
k8s.io/apimachinery v0.33.6 h1:Pq+px1i1t7lNgE58dIeBwJh7OWId6pfGD1dYBm/U5HI=
k8s.io/apimachinery v0.33.6/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/api v0.33.7 h1:Koh06KurzmXwCwe/DOaIiM1A8vEXTZ6B1tTDnmLLfxw=
k8s.io/api v0.33.7/go.mod h1:pu6qwFzTj0ijPbNYAbMgLFDEWgLFu2VUB6PVvQNtswc=
k8s.io/apimachinery v0.33.7 h1:f1kF3V+Stdr+2IGB8QhrfZ6J9JkXF6e1gWX2wKP5slU=
k8s.io/apimachinery v0.33.7/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=

View File

@@ -7,9 +7,9 @@ replace go.pinniped.dev/generated/1.33/apis => ../apis
require (
go.pinniped.dev/generated/1.33/apis v0.0.0
k8s.io/api v0.33.6
k8s.io/apimachinery v0.33.6
k8s.io/client-go v0.33.6
k8s.io/api v0.33.7
k8s.io/apimachinery v0.33.7
k8s.io/client-go v0.33.7
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff
)

View File

@@ -132,12 +132,12 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.33.6 h1:9O22ZqwT6CkQ3iboVpvTR5BEWuT3Xm6/8NX6MOLmc38=
k8s.io/api v0.33.6/go.mod h1:bdon4pRFmRmdsFyltGIoCaPqutN7y//OQ4srD0uy9X0=
k8s.io/apimachinery v0.33.6 h1:Pq+px1i1t7lNgE58dIeBwJh7OWId6pfGD1dYBm/U5HI=
k8s.io/apimachinery v0.33.6/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/client-go v0.33.6 h1:icPU5E5XHl/5mdwMUdSxpGtHnnjWzG0MSputTR9odrg=
k8s.io/client-go v0.33.6/go.mod h1:3z/Cwqdi6/Uo+E17k+OgQi4QfXS0XuIUmfHpK6rQdZU=
k8s.io/api v0.33.7 h1:Koh06KurzmXwCwe/DOaIiM1A8vEXTZ6B1tTDnmLLfxw=
k8s.io/api v0.33.7/go.mod h1:pu6qwFzTj0ijPbNYAbMgLFDEWgLFu2VUB6PVvQNtswc=
k8s.io/apimachinery v0.33.7 h1:f1kF3V+Stdr+2IGB8QhrfZ6J9JkXF6e1gWX2wKP5slU=
k8s.io/apimachinery v0.33.7/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
k8s.io/client-go v0.33.7 h1:sEcU4syZnbwaiGDctJE6G/IKsuays3wjEWGuyrD7M8c=
k8s.io/client-go v0.33.7/go.mod h1:0MEM10zY5dGdc3FdkyNCTKXiTr8P+2Vj65njzvE0Vhw=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=

View File

@@ -4,8 +4,8 @@ module go.pinniped.dev/generated/1.34/apis
go 1.24.0
require (
k8s.io/api v0.34.2
k8s.io/apimachinery v0.34.2
k8s.io/api v0.34.3
k8s.io/apimachinery v0.34.3
)
require (

View File

@@ -77,10 +77,10 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY=
k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw=
k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4=
k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4=
k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk=
k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE=
k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=

View File

@@ -7,9 +7,9 @@ replace go.pinniped.dev/generated/1.34/apis => ../apis
require (
go.pinniped.dev/generated/1.34/apis v0.0.0
k8s.io/api v0.34.2
k8s.io/apimachinery v0.34.2
k8s.io/client-go v0.34.2
k8s.io/api v0.34.3
k8s.io/apimachinery v0.34.3
k8s.io/client-go v0.34.3
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b
)

View File

@@ -136,12 +136,12 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/api v0.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY=
k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw=
k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4=
k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M=
k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE=
k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4=
k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk=
k8s.io/apimachinery v0.34.3 h1:/TB+SFEiQvN9HPldtlWOTp0hWbJ+fjU+wkxysf/aQnE=
k8s.io/apimachinery v0.34.3/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
k8s.io/client-go v0.34.3 h1:wtYtpzy/OPNYf7WyNBTj3iUA0XaBHVqhv4Iv3tbrF5A=
k8s.io/client-go v0.34.3/go.mod h1:OxxeYagaP9Kdf78UrKLa3YZixMCfP6bgPwPwNBQBzpM=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA=

20
go.mod
View File

@@ -20,7 +20,7 @@ require (
github.com/gofrs/flock v0.13.0
github.com/google/cel-go v0.26.1
github.com/google/go-cmp v0.7.0
github.com/google/go-github/v76 v76.0.0
github.com/google/go-github/v78 v78.0.0
github.com/google/gofuzz v1.2.0
github.com/google/uuid v1.6.0
github.com/gorilla/securecookie v1.1.2
@@ -38,12 +38,12 @@ require (
github.com/tdewolff/minify/v2 v2.24.8
go.uber.org/mock v0.6.0
go.uber.org/zap v1.27.1
golang.org/x/crypto v0.46.0
golang.org/x/net v0.48.0
golang.org/x/crypto v0.47.0
golang.org/x/net v0.49.0
golang.org/x/oauth2 v0.34.0
golang.org/x/sync v0.19.0
golang.org/x/term v0.38.0
golang.org/x/text v0.32.0
golang.org/x/term v0.39.0
golang.org/x/text v0.33.0
k8s.io/api v0.35.0
k8s.io/apiextensions-apiserver v0.35.0
k8s.io/apimachinery v0.35.0
@@ -53,8 +53,8 @@ require (
k8s.io/gengo v0.0.0-20251215205346-5ee0d033ba5b
k8s.io/klog/v2 v2.130.1
k8s.io/kube-aggregator v0.35.0
k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e
k8s.io/utils v0.0.0-20251222233032-718f0e51e6d2
k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4
k8s.io/utils v0.0.0-20260108192941-914a6e750570
sigs.k8s.io/yaml v1.6.0
)
@@ -159,10 +159,10 @@ require (
go.yaml.in/yaml/v2 v2.4.3 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/mod v0.30.0 // indirect
golang.org/x/sys v0.39.0 // indirect
golang.org/x/mod v0.31.0 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/time v0.11.0 // indirect
golang.org/x/tools v0.39.0 // indirect
golang.org/x/tools v0.40.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect
google.golang.org/grpc v1.72.2 // indirect

44
go.sum
View File

@@ -249,8 +249,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-github/v73 v73.0.0 h1:aR+Utnh+Y4mMkS+2qLQwcQ/cF9mOTpdwnzlaw//rG24=
github.com/google/go-github/v73 v73.0.0/go.mod h1:fa6w8+/V+edSU0muqdhCVY7Beh1M8F1IlQPZIANKIYw=
github.com/google/go-github/v76 v76.0.0 h1:MCa9VQn+VG5GG7Y7BAkBvSRUN3o+QpaEOuZwFPJmdFA=
github.com/google/go-github/v76 v76.0.0/go.mod h1:38+d/8pYDO4fBLYfBhXF5EKO0wA3UkXBjfmQapFsNCQ=
github.com/google/go-github/v78 v78.0.0 h1:b1tytzFE8i//lRVDx5Qh/EdJbtTPtSVD3nF7hraEs9w=
github.com/google/go-github/v78 v78.0.0/go.mod h1:Uxvdzy82AkNlC6JQ57se9TqvmgBT7RF0ouHDNg2jd6g=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -688,8 +688,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
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=
@@ -728,8 +728,8 @@ golang.org/x/mod v0.4.1/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.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
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=
@@ -769,8 +769,8 @@ golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfS
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
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.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
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=
@@ -850,10 +850,10 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 h1:E2/AqCUMZGgd73TQkxUMcMla25GB9i/5HOdLr+uH7Vo=
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc h1:bH6xUXay0AIFMElXG2rQ4uiE+7ncwtiOdPfYK1NK2XA=
golang.org/x/telemetry v0.0.0-20251203150158-8fff8a5912fc/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ=
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=
@@ -862,8 +862,8 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
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.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY=
golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww=
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=
@@ -875,8 +875,8 @@ 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/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
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=
@@ -940,8 +940,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
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.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
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=
@@ -1096,10 +1096,10 @@ k8s.io/kms v0.35.0 h1:/x87FED2kDSo66csKtcYCEHsxF/DBlNl7LfJ1fVQs1o=
k8s.io/kms v0.35.0/go.mod h1:VT+4ekZAdrZDMgShK37vvlyHUVhwI9t/9tvh0AyCWmQ=
k8s.io/kube-aggregator v0.35.0 h1:FBtbuRFA7Ohe2QKirFZcJf8rgimC8oSaNiCi4pdU5xw=
k8s.io/kube-aggregator v0.35.0/go.mod h1:vKBRpQUfDryb7udwUwF3eCSvv3AJNgHtL4PGl6PqAg8=
k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e h1:iW9ChlU0cU16w8MpVYjXk12dqQ4BPFBEgif+ap7/hqQ=
k8s.io/kube-openapi v0.0.0-20251125145642-4e65d59e963e/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
k8s.io/utils v0.0.0-20251222233032-718f0e51e6d2 h1:OfgiEo21hGiwx1oJUU5MpEaeOEg6coWndBkZF/lkFuE=
k8s.io/utils v0.0.0-20251222233032-718f0e51e6d2/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4 h1:HhDfevmPS+OalTjQRKbTHppRIz01AWi8s45TMXStgYY=
k8s.io/kube-openapi v0.0.0-20260127142750-a19766b6e2d4/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ=
k8s.io/utils v0.0.0-20260108192941-914a6e750570 h1:JT4W8lsdrGENg9W+YwwdLJxklIuKWdRm+BC+xt33FOY=
k8s.io/utils v0.0.0-20260108192941-914a6e750570/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk=
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

@@ -1,6 +1,6 @@
# syntax=docker/dockerfile:1
# Copyright 2022-2025 the Pinniped contributors. All Rights Reserved.
# Copyright 2022-2026 the Pinniped contributors. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
# this dockerfile is used to produce a binary of Pinniped that uses
@@ -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.25.5@sha256:36b4f45d2874905b9e8573b783292629bcb346d0a70d8d7150b6df545234818f
ARG BASE_IMAGE=gcr.io/distroless/static:nonroot@sha256:2b7c93f6d6648c11f0e80a48558c8f77885eb0445213b8e69a6a0d7c89fc6ae4
ARG BUILD_IMAGE=golang:1.25.6@sha256:ce63a16e0f7063787ebb4eb28e72d477b00b4726f79874b3205a965ffd797ab2
ARG BASE_IMAGE=gcr.io/distroless/static:nonroot@sha256:cba10d7abd3e203428e86f5b2d7fd5eb7d8987c387864ae4996cf97191b33764
# 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

@@ -13,8 +13,8 @@
# is edited in this file, please run hack/update.sh.
#
1.35.0
1.34.2
1.33.6
1.32.10
1.34.3
1.33.7
1.32.11
1.31.14
1.30.14

View File

@@ -1,15 +1,10 @@
#!/bin/bash
# Copyright 2021-2024 the Pinniped contributors. All Rights Reserved.
# Copyright 2021-2026 the Pinniped contributors. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
set -euo pipefail
if [[ "$OSTYPE" != "darwin"* ]]; then
echo "This script was only written for MacOS (due to differences with Linux sed flags)"
exit 1
fi
files=$(git diff --cached --name-only)
year=$(date +"%Y")
@@ -25,15 +20,25 @@ done
if [[ "${#missing_copyright_files[@]}" -gt "0" ]]; then
echo "Fixing copyright notice in the following files:"
for f in "${missing_copyright_files[@]}"; do
echo " $f"
# The rule when updating copyrights is to always keep the starting year,
# and to replace the ending year with the current year.
# This uses MacOS sed flags to replace "XXXX-YYYY" with "XXXX-year" in the copyright notice.
sed -E -e 's/Copyright ([0-9]{4})-([0-9]{4}) the Pinniped contributors/Copyright \1-'"$year"' the Pinniped contributors/' -i '' "$f"
# This uses MacOS sed flags to replace "XXXX" with "XXXX-year" in the copyright notice.
sed -E -e 's/Copyright ([0-9]{4}) the Pinniped contributors/Copyright \1-'"$year"' the Pinniped contributors/' -i '' "$f"
if [[ "$(uname -s)" == "Linux" ]]; then
# sed on Linux uses -i'' (no space in between).
# Replace "XXXX-YYYY" with "XXXX-year" in the copyright notice.
sed -E -e 's/Copyright ([0-9]{4})-([0-9]{4}) the Pinniped contributors/Copyright \1-'"$year"' the Pinniped contributors/' -i'' "$f"
# Replace "XXXX" with "XXXX-year" in the copyright notice.
sed -E -e 's/Copyright ([0-9]{4}) the Pinniped contributors/Copyright \1-'"$year"' the Pinniped contributors/' -i'' "$f"
else
# sed on MacOS uses -i '' (with space in between).
# Replace "XXXX-YYYY" with "XXXX-year" in the copyright notice.
sed -E -e 's/Copyright ([0-9]{4})-([0-9]{4}) the Pinniped contributors/Copyright \1-'"$year"' the Pinniped contributors/' -i '' "$f"
# Replace "XXXX" with "XXXX-year" in the copyright notice.
sed -E -e 's/Copyright ([0-9]{4}) the Pinniped contributors/Copyright \1-'"$year"' the Pinniped contributors/' -i '' "$f"
fi
done
echo "Done!"
exit 1
fi

View File

@@ -2,4 +2,4 @@ module go.pinniped.dev/update-go-mod
go 1.25.0
require golang.org/x/mod v0.29.0
require golang.org/x/mod v0.32.0

View File

@@ -1,2 +1,2 @@
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
golang.org/x/mod v0.32.0 h1:9F4d3PHLljb6x//jOyokMv3eX+YDeepZSEo3mFJy93c=
golang.org/x/mod v0.32.0/go.mod h1:SgipZ/3h2Ci89DlEtEXWUk/HteuRin+HHhN+WbNhguU=

View File

@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# Copyright 2024 the Pinniped contributors. All Rights Reserved.
# Copyright 2024-2026 the Pinniped contributors. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
set -euo pipefail
@@ -36,30 +36,26 @@ for m in $modules; do
found_new_version=$?
if [[ $found_new_version == 0 ]]; then
echo "Found new version $next_version. Replacing imports..."
find . -name './.*' -prune -o \
-path ./generated -prune -o \
-type f -name '*.go' -print0 |
xargs -0 sed -i '' "s#${m}#${next_version}#g"
if [[ "$(uname -s)" == "Linux" ]]; then
# sed on Linux uses -i'' (no space in between).
find . -wholename './.*' -prune -o \
-path ./generated -prune -o \
-type f -name '*.go' -print0 |
xargs -0 sed -i'' "s#${m}#${next_version}#g"
else
# sed on MacOS uses -i '' (with space in between).
find . -wholename './.*' -prune -o \
-path ./generated -prune -o \
-type f -name '*.go' -print0 |
xargs -0 sed -i '' "s#${m}#${next_version}#g"
fi
fi
set -e
done
go mod tidy
if git diff --quiet; then
echo
echo "No changes."
else
echo
echo "Showing resulting diffs..."
git --no-pager diff
echo
echo "Running unit tests..."
./hack/module.sh units
fi
popd >/dev/null
echo
echo "Done!"
echo "Done updating majors! Check for git diffs to see results."

View File

@@ -1,4 +1,4 @@
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2026 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package impersonator
@@ -236,12 +236,12 @@ func newInternal(
serverConfig.AuditPolicyRuleEvaluator = policy.NewFakePolicyRuleEvaluator(auditinternal.LevelMetadata, nil)
serverConfig.AuditBackend = &auditfake.Backend{}
// Probe the API server to figure out if anonymous auth is enabled.
anonymousAuthEnabled, err := isAnonymousAuthEnabled(kubeClientUnsafeForProxying.JSONConfig)
// Probe the Kubernetes API server to figure out if anonymous auth is enabled.
anonymousAuthProbeResult, err := isAnonymousAuthEnabled(kubeClientUnsafeForProxying.JSONConfig)
if err != nil {
return nil, fmt.Errorf("could not detect if anonymous authentication is enabled: %w", err)
}
plog.Debug("anonymous authentication probed", "anonymousAuthEnabled", anonymousAuthEnabled)
plog.Debug("anonymous authentication probed", "results", anonymousAuthProbeResult)
// if we ever start unioning a TCR bearer token authenticator with serverConfig.Authenticator
// then we will need to update the related assumption in tokenPassthroughRoundTripper
@@ -251,8 +251,15 @@ func newInternal(
RequestFunc: func(req *http.Request) (*authenticator.Response, bool, error) {
resp, ok, err := delegatingAuthenticator.AuthenticateRequest(req)
// anonymous auth is enabled so no further check is necessary
if anonymousAuthEnabled {
reqIsHealthCheck := isRequestForHealthCheck(req)
if anonymousAuthProbeResult.HealthCheckEndpointsAllowAnonAuth && reqIsHealthCheck {
// anonymous auth is enabled for health check endpoints, so no further check is necessary
return resp, ok, err
}
if anonymousAuthProbeResult.OtherEndpointsAllowAnonAuth && !reqIsHealthCheck {
// anonymous auth is enabled for all other endpoints, so no further check is necessary
return resp, ok, err
}
@@ -266,6 +273,10 @@ func newInternal(
return resp, ok, err
}
// If we got this far, then anonymous auth is disabled for this request's path,
// and authentication succeeded, and the user is system:anonymous.
// Now we want to allow these anonymous users to make requests _only_ to the TCR endpoint.
reqInfo, ok := genericapirequest.RequestInfoFrom(req.Context())
if !ok {
return nil, false, constable.Error("no RequestInfo found in the context")
@@ -276,7 +287,7 @@ func newInternal(
return nil, false, nil
}
// any resource besides TKR should not be authenticated
// any resource besides TKR should not be authenticated because anonymous auth is disabled on this cluster
if !isTokenCredReq(reqInfo) {
return nil, false, nil
}
@@ -370,7 +381,46 @@ func getReverseProxyClient(baseConfig *rest.Config, cache tokenclient.ExpiringSi
return kubeclient.New(kubeclient.WithConfig(impersonationProxyRestConfig))
}
func isAnonymousAuthEnabled(config *rest.Config) (bool, error) {
func isRequestForHealthCheck(req *http.Request) bool {
if req == nil || req.URL == nil {
// Shouldn't really happen but easy enough to handle here.
return false
}
path := req.URL.Path
// See https://kubernetes.io/docs/reference/using-api/health-checks.
// Although there are sub-paths for these endpoints, e.g. /healthz/etcd, the sub-paths are not made available
// for anonymous auth by GKE when anonymous auth is otherwise disabled, so let's mirror that behavior here.
switch path {
case "/healthz", "/readyz", "/livez":
return true
default:
return false
}
}
// anonAuthEnablement allows us to characterize the most common configurations for anonymous authentication:
//
// 1. Anonymous auth is disabled for the whole k8s API (e.g. AKS clusters).
// 2. Anonymous auth is enabled for the whole k8s API (e.g. GKE clusters before Kubernetes 1.35).
// 3. In newer clusters, anonymous auth can be selectively enabled only for certain API paths.
// See https://kubernetes.io/docs/reference/access-authn-authz/authentication/#anonymous-authenticator-configuration.
// Usually this is used to enable anonymous auth only for the three health check endpoints, and disable it for
// all other endpoints. This configuration was adpoted by GKE clusters starting with Kube 1.35 (as the default, but
// can be overridden by the user during cluster creation to instead allow anon auth for the whole API)
// and by EKS clusters starting with Kube 1.32.
//
// Of course, other configurations of which API paths allow should anonymous auth are possible, but we have no practical
// way of auto-detecting them here. We could alternatively add new Pinniped configuration options instead of trying to
// auto-detect anonymous authentication enablement here, but that would put extra burdon on the user to configure it
// correctly. In practice, its almost always one of the three configurations described above.
type anonAuthEnablement struct {
HealthCheckEndpointsAllowAnonAuth bool
OtherEndpointsAllowAnonAuth bool
}
func isAnonymousAuthEnabled(config *rest.Config) (*anonAuthEnablement, error) {
anonymousConfig := kubeclient.SecureAnonymousClientConfig(config)
// we do not need either of these but RESTClientFor complains if they are not set
@@ -380,32 +430,54 @@ func isAnonymousAuthEnabled(config *rest.Config) (bool, error) {
// in case anyone looking at audit logs wants to know who is making the anonymous request
anonymousConfig.UserAgent = rest.DefaultKubernetesUserAgent()
rc, err := rest.RESTClientFor(anonymousConfig)
anonClient, err := rest.RESTClientFor(anonymousConfig)
if err != nil {
return false, err
return nil, err
}
healthzAllowsAnonAuth, err := isAnonymousAuthEnabledForEndpoint(anonClient.Get().AbsPath("/healthz"))
if err != nil {
return nil, fmt.Errorf("error from healthz API: %w", err)
}
// As a heuristic to determine if anonymous auth is enabled for all other API endpoints,
// we probe one representative endpoint which should exist on all clusters. We assume that
// the result found at this endpoint is representative of the result for all non-heath endpoints.
otherAPIAllowsAnonAuth, err := isAnonymousAuthEnabledForEndpoint(
anonClient.Get().AbsPath("/api/v1/nodes").Param("limit", "1"),
)
if err != nil {
return nil, fmt.Errorf("error from v1 nodes API: %w", err)
}
return &anonAuthEnablement{
HealthCheckEndpointsAllowAnonAuth: healthzAllowsAnonAuth,
OtherEndpointsAllowAnonAuth: otherAPIAllowsAnonAuth,
}, nil
}
func isAnonymousAuthEnabledForEndpoint(anonReq *rest.Request) (bool, error) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
_, errHealthz := rc.Get().AbsPath("/healthz").DoRaw(ctx)
_, err := anonReq.DoRaw(ctx)
switch {
// 200 ok on healthz clearly indicates authentication success
case errHealthz == nil:
// 200 ok clearly indicates authentication success
case err == nil:
return true, nil
// we are authenticated but not authorized. anonymous authentication is enabled
case apierrors.IsForbidden(errHealthz):
// we are authenticated but not authorized: anonymous authentication is enabled at the endpoint
case apierrors.IsForbidden(err):
return true, nil
// failure to authenticate will return unauthorized (http misnomer)
case apierrors.IsUnauthorized(errHealthz):
case apierrors.IsUnauthorized(err):
return false, nil
// any other error is unexpected
default:
return false, errHealthz
return false, err
}
}

View File

@@ -1,4 +1,4 @@
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2026 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package impersonator
@@ -101,19 +101,21 @@ func TestImpersonator(t *testing.T) {
}
tests := []struct {
name string
clientCert clientCert
clientImpersonateUser rest.ImpersonationConfig
clientMutateHeaders func(http.Header)
clientNextProtos []string
kubeAPIServerStatusCode int
kubeAPIServerHealthz http.Handler
anonymousAuthDisabled bool
noServiceAcctTokenInCache bool // when true, no available service account token for the impersonator to use
wantKubeAPIServerRequestHeaders func(credentialID string) http.Header
wantError string
wantConstructionError string
wantAuthorizerAttributes func(credentialID string) []authorizer.AttributesRecord
name string
clientCert clientCert
clientImpersonateUser rest.ImpersonationConfig
clientMutateHeaders func(http.Header)
clientNextProtos []string
kubeAPIServerStatusCode int
kubeAPIServerHealthz http.Handler
kubeAPIServerNodes http.Handler
anonymousAuthForHealthDisabled bool
anonymousAuthForOtherAPIsDisabled bool
noServiceAcctTokenInCache bool // when true, no available service account token for the impersonator to use
wantKubeAPIServerRequestHeaders func(credentialID string) http.Header
wantError string
wantConstructionError string
wantAuthorizerAttributes func(credentialID string) []authorizer.AttributesRecord
}{
{
name: "happy path",
@@ -140,7 +142,7 @@ func TestImpersonator(t *testing.T) {
},
},
{
name: "happy path with forbidden healthz",
name: "happy path with forbidden healthz (anonymous auth for health checks is allowed)",
clientCert: newClientCert(t, ca, "test-username", []string{"test-group1", "test-group2"}),
kubeAPIServerHealthz: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusForbidden)
@@ -168,13 +170,104 @@ func TestImpersonator(t *testing.T) {
},
},
{
name: "happy path with unauthorized healthz",
name: "happy path with forbidden nodes (anonymous auth for other APIs is allowed)",
clientCert: newClientCert(t, ca, "test-username", []string{"test-group1", "test-group2"}),
kubeAPIServerNodes: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusForbidden)
_, _ = w.Write([]byte("no nodes for you"))
}),
wantKubeAPIServerRequestHeaders: func(credentialID string) http.Header {
return http.Header{
"Impersonate-User": {"test-username"},
"Impersonate-Group": {"test-group1", "test-group2", "system:authenticated"},
"Authorization": {"Bearer some-service-account-token"},
"User-Agent": {"test-agent"},
"Accept": {"application/vnd.kubernetes.protobuf,application/json"},
"Accept-Encoding": {"gzip"},
"X-Forwarded-For": {"127.0.0.1"},
"Impersonate-Extra-Authentication.kubernetes.io%2fcredential-Id": {credentialID},
}
},
wantAuthorizerAttributes: func(credentialID string) []authorizer.AttributesRecord {
return []authorizer.AttributesRecord{
{
User: defaultInfoForTestUsername(credentialID),
Verb: "list", Namespace: "", APIGroup: "", APIVersion: "v1", Resource: "namespaces", Subresource: "", Name: "", ResourceRequest: true, Path: "/api/v1/namespaces",
},
}
},
},
{
name: "happy path with unauthorized healthz (anonymous auth for health checks is disallowed)",
clientCert: newClientCert(t, ca, "test-username", []string{"test-group1", "test-group2"}),
kubeAPIServerHealthz: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusUnauthorized)
_, _ = w.Write([]byte("no healthz for you"))
}),
anonymousAuthDisabled: true,
anonymousAuthForHealthDisabled: true,
wantKubeAPIServerRequestHeaders: func(credentialID string) http.Header {
return http.Header{
"Impersonate-User": {"test-username"},
"Impersonate-Group": {"test-group1", "test-group2", "system:authenticated"},
"Authorization": {"Bearer some-service-account-token"},
"User-Agent": {"test-agent"},
"Accept": {"application/vnd.kubernetes.protobuf,application/json"},
"Accept-Encoding": {"gzip"},
"X-Forwarded-For": {"127.0.0.1"},
"Impersonate-Extra-Authentication.kubernetes.io%2fcredential-Id": {credentialID},
}
},
wantAuthorizerAttributes: func(credentialID string) []authorizer.AttributesRecord {
return []authorizer.AttributesRecord{
{
User: defaultInfoForTestUsername(credentialID),
Verb: "list", Namespace: "", APIGroup: "", APIVersion: "v1", Resource: "namespaces", Subresource: "", Name: "", ResourceRequest: true, Path: "/api/v1/namespaces",
},
}
},
},
{
name: "happy path with unauthorized nodes (anonymous auth for other APIs is disallowed)",
clientCert: newClientCert(t, ca, "test-username", []string{"test-group1", "test-group2"}),
kubeAPIServerNodes: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusUnauthorized)
_, _ = w.Write([]byte("no nodes for you"))
}),
anonymousAuthForOtherAPIsDisabled: true,
wantKubeAPIServerRequestHeaders: func(credentialID string) http.Header {
return http.Header{
"Impersonate-User": {"test-username"},
"Impersonate-Group": {"test-group1", "test-group2", "system:authenticated"},
"Authorization": {"Bearer some-service-account-token"},
"User-Agent": {"test-agent"},
"Accept": {"application/vnd.kubernetes.protobuf,application/json"},
"Accept-Encoding": {"gzip"},
"X-Forwarded-For": {"127.0.0.1"},
"Impersonate-Extra-Authentication.kubernetes.io%2fcredential-Id": {credentialID},
}
},
wantAuthorizerAttributes: func(credentialID string) []authorizer.AttributesRecord {
return []authorizer.AttributesRecord{
{
User: defaultInfoForTestUsername(credentialID),
Verb: "list", Namespace: "", APIGroup: "", APIVersion: "v1", Resource: "namespaces", Subresource: "", Name: "", ResourceRequest: true, Path: "/api/v1/namespaces",
},
}
},
},
{
name: "happy path with unauthorized healthz and nodes (anonymous auth for everything is disallowed)",
clientCert: newClientCert(t, ca, "test-username", []string{"test-group1", "test-group2"}),
kubeAPIServerHealthz: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusUnauthorized)
_, _ = w.Write([]byte("no healthz for you"))
}),
kubeAPIServerNodes: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusUnauthorized)
_, _ = w.Write([]byte("no nodes for you"))
}),
anonymousAuthForHealthDisabled: true,
anonymousAuthForOtherAPIsDisabled: true,
wantKubeAPIServerRequestHeaders: func(credentialID string) http.Header {
return http.Header{
"Impersonate-User": {"test-username"},
@@ -747,7 +840,16 @@ func TestImpersonator(t *testing.T) {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte("broken"))
}),
wantConstructionError: `could not detect if anonymous authentication is enabled: an error on the server ("broken") has prevented the request from succeeding`,
wantConstructionError: `could not detect if anonymous authentication is enabled: error from healthz API: an error on the server ("broken") has prevented the request from succeeding`,
wantAuthorizerAttributes: nil,
},
{
name: "unexpected nodes response",
kubeAPIServerNodes: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte("broken"))
}),
wantConstructionError: `could not detect if anonymous authentication is enabled: error from v1 nodes API: an error on the server ("broken") has prevented the request from succeeding`,
wantAuthorizerAttributes: nil,
},
{
@@ -832,7 +934,7 @@ func TestImpersonator(t *testing.T) {
var testKubeAPIServerSawHeaders http.Header
testKubeAPIServer, testKubeAPIServerCA := tlsserver.TestServerIPv4(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
tlsConfigFunc := func(rootCAs *x509.CertPool) *tls.Config {
// Requests to get configmaps, flowcontrol requests, and healthz requests
// Requests to get configmaps, nodes, flowcontrol requests, and healthz requests
// are not done by our http round trippers that specify only one protocol
// (either http1.1 or http2, not both).
// For all other requests from the impersonator, if it is not an upgrade
@@ -844,7 +946,8 @@ func TestImpersonator(t *testing.T) {
case "/api/v1/namespaces/kube-system/configmaps",
fmt.Sprintf("/apis/flowcontrol.apiserver.k8s.io/%s/prioritylevelconfigurations", priorityLevelConfigurationsVersion),
fmt.Sprintf("/apis/flowcontrol.apiserver.k8s.io/%s/flowschemas", flowSchemasVersion),
"/healthz":
"/healthz",
"/api/v1/nodes":
default:
if !httpstream.IsUpgradeRequest(r) {
secure.NextProtos = []string{secure.NextProtos[0]}
@@ -900,6 +1003,15 @@ func TestImpersonator(t *testing.T) {
_, _ = fmt.Fprint(w, "probed")
return
case "/readyz", "/readyz/etcd", "/livez":
require.Equal(t, http.MethodGet, r.Method)
// match the KAS endpoint's behavior
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.Header().Set("X-Content-Type-Options", "nosniff")
_, _ = fmt.Fprint(w, "ok")
return
case "/healthz":
require.Equal(t, http.MethodGet, r.Method)
require.Empty(t, r.Header.Get("Authorization"))
@@ -916,6 +1028,24 @@ func TestImpersonator(t *testing.T) {
_, _ = fmt.Fprint(w, "ok")
return
case "/api/v1/nodes":
// In these tests, the test client doesn't call the nodes API through the impersonator,
// but the impersonator production code uses the nodes API to probe whether anonymous auth
// is enabled or not, similar to what it does with the healthz API.
require.Equal(t, http.MethodGet, r.Method)
require.Empty(t, r.Header.Get("Authorization"))
require.Contains(t, r.Header.Get("User-Agent"), "kubernetes")
if tt.kubeAPIServerNodes != nil {
tt.kubeAPIServerNodes.ServeHTTP(w, r)
return
}
// by default just return success
w.Header().Add("Content-Type", "application/json; charset=UTF-8")
_, _ = fmt.Fprint(w, `{}`)
return
case "/apis/login.concierge.pinniped.dev/v1alpha1/tokencredentialrequests":
require.Equal(t, http.MethodPost, r.Method)
@@ -1142,8 +1272,40 @@ func TestImpersonator(t *testing.T) {
rc, err := rest.RESTClientFor(anonymousConfig)
require.NoError(t, err)
// It would be nice to also call /healthz through the impersonator here, but this unit test makes it
// difficult because of the expectations that it sets differently for APIs that are expected to be called
// by external clients versus those expected to be called by the impersonator itself.
// We can test calling /readyz and /livez, but note that calling /healthz should also work the same.
readyzBody, errReadyz := rc.Get().AbsPath("/readyz").DoRaw(ctx)
if tt.anonymousAuthForHealthDisabled {
require.True(t, apierrors.IsUnauthorized(errReadyz), errReadyz)
require.Equal(t, `{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Unauthorized","reason":"Unauthorized","code":401}`+"\n", string(readyzBody))
} else {
require.NoError(t, errReadyz)
require.Equal(t, "ok", string(readyzBody))
}
// We don't treat sub-paths of health check endpoints as health check endpoints. Treat sub-paths as "other" endpoints.
readyzEtcdBody, errReadyzEtcd := rc.Get().AbsPath("/readyz/etcd").DoRaw(ctx)
if tt.anonymousAuthForOtherAPIsDisabled {
require.True(t, apierrors.IsUnauthorized(errReadyzEtcd), errReadyzEtcd)
require.Equal(t, `{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Unauthorized","reason":"Unauthorized","code":401}`+"\n", string(readyzEtcdBody))
} else {
require.NoError(t, errReadyzEtcd)
require.Equal(t, "ok", string(readyzEtcdBody))
}
livezBody, errLivez := rc.Get().AbsPath("/livez").DoRaw(ctx)
if tt.anonymousAuthForHealthDisabled {
require.True(t, apierrors.IsUnauthorized(errLivez), errLivez)
require.Equal(t, `{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Unauthorized","reason":"Unauthorized","code":401}`+"\n", string(livezBody))
} else {
require.NoError(t, errLivez)
require.Equal(t, "ok", string(livezBody))
}
probeBody, errProbe := rc.Get().AbsPath("/probe").DoRaw(ctx)
if tt.anonymousAuthDisabled {
if tt.anonymousAuthForOtherAPIsDisabled {
require.True(t, apierrors.IsUnauthorized(errProbe), errProbe)
require.Equal(t, `{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Unauthorized","reason":"Unauthorized","code":401}`+"\n", string(probeBody))
} else {
@@ -1151,8 +1313,9 @@ func TestImpersonator(t *testing.T) {
require.Equal(t, "probed", string(probeBody))
}
// Fetch other resource that just happens to also be called tokencredentialrequests, but belongs to a different API group/version.
notTCRBody, errNotTCR := rc.Get().Resource("tokencredentialrequests").DoRaw(ctx)
if tt.anonymousAuthDisabled {
if tt.anonymousAuthForOtherAPIsDisabled {
require.True(t, apierrors.IsUnauthorized(errNotTCR), errNotTCR)
require.Equal(t, `{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Unauthorized","reason":"Unauthorized","code":401}`+"\n", string(notTCRBody))
} else {
@@ -1161,7 +1324,7 @@ func TestImpersonator(t *testing.T) {
}
ducksBody, errDucks := rc.Get().Resource("ducks").DoRaw(ctx)
if tt.anonymousAuthDisabled {
if tt.anonymousAuthForOtherAPIsDisabled {
require.True(t, apierrors.IsUnauthorized(errDucks), errDucks)
require.Equal(t, `{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Unauthorized","reason":"Unauthorized","code":401}`+"\n", string(ducksBody))
} else {
@@ -1194,8 +1357,24 @@ func TestImpersonator(t *testing.T) {
Verb: "create", Namespace: "", APIGroup: "login.concierge.walrus.tld", APIVersion: "v1alpha1", Resource: "tokencredentialrequests", Subresource: "", Name: "", ResourceRequest: true, Path: "/apis/login.concierge.walrus.tld/v1alpha1/tokencredentialrequests",
},
)
if !tt.anonymousAuthDisabled {
if !tt.anonymousAuthForHealthDisabled {
wantAuthorizerAttributes = append(wantAuthorizerAttributes,
authorizer.AttributesRecord{
User: &user.DefaultInfo{Name: "system:anonymous", UID: "", Groups: []string{"system:unauthenticated"}, Extra: nil},
Verb: "get", Namespace: "", APIGroup: "", APIVersion: "", Resource: "", Subresource: "", Name: "", ResourceRequest: false, Path: "/readyz",
},
authorizer.AttributesRecord{
User: &user.DefaultInfo{Name: "system:anonymous", UID: "", Groups: []string{"system:unauthenticated"}, Extra: nil},
Verb: "get", Namespace: "", APIGroup: "", APIVersion: "", Resource: "", Subresource: "", Name: "", ResourceRequest: false, Path: "/livez",
},
)
}
if !tt.anonymousAuthForOtherAPIsDisabled {
wantAuthorizerAttributes = append(wantAuthorizerAttributes,
authorizer.AttributesRecord{
User: &user.DefaultInfo{Name: "system:anonymous", UID: "", Groups: []string{"system:unauthenticated"}, Extra: nil},
Verb: "get", Namespace: "", APIGroup: "", APIVersion: "", Resource: "", Subresource: "", Name: "", ResourceRequest: false, Path: "/readyz/etcd",
},
authorizer.AttributesRecord{
User: &user.DefaultInfo{Name: "system:anonymous", UID: "", Groups: []string{"system:unauthenticated"}, Extra: nil},
Verb: "get", Namespace: "", APIGroup: "", APIVersion: "", Resource: "", Subresource: "", Name: "", ResourceRequest: false, Path: "/probe",
@@ -2262,3 +2441,77 @@ func (r *attributeRecorder) record(attributes authorizer.Attributes) {
defer r.lock.Unlock()
r.attributes = append(r.attributes, *attributes.(*authorizer.AttributesRecord))
}
func Test_isRequestForHealthCheck(t *testing.T) {
tests := []struct {
path string
want bool
}{
{
path: "/healthz",
want: true,
},
{
path: "/livez",
want: true,
},
{
path: "/readyz",
want: true,
},
{
path: "/healthz/anything",
want: false,
},
{
path: "/livez/anything",
want: false,
},
{
path: "/readyz/anything",
want: false,
},
{
path: "/readyz/anything/",
want: false,
},
{
path: "/healthz/",
want: false,
},
{
path: "/livez/",
want: false,
},
{
path: "/readyz/",
want: false,
},
{
path: "/other",
want: false,
},
{
path: "/something/else",
want: false,
},
}
for _, tt := range tests {
t.Run(tt.path, func(t *testing.T) {
u := url.URL{Path: tt.path}
got := isRequestForHealthCheck(&http.Request{URL: &u})
require.Equal(t, tt.want, got)
})
}
t.Run("nil req", func(t *testing.T) {
got := isRequestForHealthCheck(nil)
require.False(t, got)
})
t.Run("nil URL", func(t *testing.T) {
got := isRequestForHealthCheck(&http.Request{})
require.False(t, got)
})
}

View File

@@ -1,4 +1,4 @@
// Copyright 2024-2025 the Pinniped contributors. All Rights Reserved.
// Copyright 2024-2026 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package githubclient
@@ -12,7 +12,7 @@ import (
"slices"
"strings"
"github.com/google/go-github/v76/github"
"github.com/google/go-github/v78/github"
"k8s.io/apimachinery/pkg/util/sets"
"go.pinniped.dev/internal/plog"

View File

@@ -1,4 +1,4 @@
// Copyright 2024-2025 the Pinniped contributors. All Rights Reserved.
// Copyright 2024-2026 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package githubclient
@@ -9,7 +9,7 @@ import (
"strings"
"testing"
"github.com/google/go-github/v76/github"
"github.com/google/go-github/v78/github"
"github.com/migueleliasweb/go-github-mock/src/mock"
"github.com/stretchr/testify/require"
"k8s.io/client-go/util/cert"

View File

@@ -7,8 +7,8 @@ params:
github_url: "https://github.com/vmware/pinniped"
slack_url: "https://go.pinniped.dev/community/slack"
community_url: "https://go.pinniped.dev/community"
latest_version: v0.42.0
latest_codegen_version: 1.33
latest_version: v0.44.0
latest_codegen_version: 1.35
pygmentsCodefences: true
pygmentsStyle: "pygments"
markup:

View File

@@ -1,4 +1,4 @@
# Copyright 2021 the Pinniped contributors. All Rights Reserved.
# Copyright 2021-2026 the Pinniped contributors. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
# The name of the cluster type.
@@ -13,9 +13,13 @@ capabilities:
# Will the cluster successfully provision a load balancer if requested?
hasExternalLoadBalancerProvider: true
# Does the cluster allow requests without authentication?
# https://kubernetes.io/docs/reference/access-authn-authz/authentication/#anonymous-requests
anonymousAuthenticationSupported: false
# Are LDAP ports on the Internet reachable without interference from network firewalls or proxies?
canReachInternetLDAPPorts: true
# Does the cluster allow requests without authentication?
# https://kubernetes.io/docs/reference/access-authn-authz/authentication/#anonymous-requests
anonymousAuthentication:
healthEndpoints:
allowed: false
otherEndpoints:
allowed: false

View File

@@ -1,4 +1,4 @@
# Copyright 2021 the Pinniped contributors. All Rights Reserved.
# Copyright 2021-2026 the Pinniped contributors. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
# The name of the cluster type.
@@ -13,9 +13,14 @@ capabilities:
# Will the cluster successfully provision a load balancer if requested?
hasExternalLoadBalancerProvider: true
# Does the cluster allow requests without authentication?
# https://kubernetes.io/docs/reference/access-authn-authz/authentication/#anonymous-requests
anonymousAuthenticationSupported: true
# Are LDAP ports on the Internet reachable without interference from network firewalls or proxies?
canReachInternetLDAPPorts: true
# Does the cluster allow requests without authentication?
# https://kubernetes.io/docs/reference/access-authn-authz/authentication/#anonymous-requests
# Amazon disabled anonymous authentication in EKS clusters starting with k8s 1.32.
anonymousAuthentication:
healthEndpoints:
allowed: true
otherEndpoints:
allowedIfK8sMinorVersionLessThan: 32

View File

@@ -1,4 +1,4 @@
# Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
# Copyright 2020-2026 the Pinniped contributors. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
# The name of the cluster type.
@@ -13,9 +13,14 @@ capabilities:
# Will the cluster successfully provision a load balancer if requested?
hasExternalLoadBalancerProvider: true
# Does the cluster allow requests without authentication?
# https://kubernetes.io/docs/reference/access-authn-authz/authentication/#anonymous-requests
anonymousAuthenticationSupported: true
# Are LDAP ports on the Internet reachable without interference from network firewalls or proxies?
canReachInternetLDAPPorts: true
# Does the cluster allow requests without authentication?
# https://kubernetes.io/docs/reference/access-authn-authz/authentication/#anonymous-requests
# Google disabled anonymous authentication in GKE clusters by default starting with k8s 1.35.
anonymousAuthentication:
healthEndpoints:
allowed: true
otherEndpoints:
allowedIfK8sMinorVersionLessThan: 35

View File

@@ -1,4 +1,4 @@
# Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
# Copyright 2020-2026 the Pinniped contributors. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
# The name of the cluster type.
@@ -13,9 +13,13 @@ capabilities:
# Will the cluster successfully provision a load balancer if requested?
hasExternalLoadBalancerProvider: false
# Does the cluster allow requests without authentication?
# https://kubernetes.io/docs/reference/access-authn-authz/authentication/#anonymous-requests
anonymousAuthenticationSupported: true
# Are LDAP ports on the Internet reachable without interference from network firewalls or proxies?
canReachInternetLDAPPorts: true
# Does the cluster allow requests without authentication?
# https://kubernetes.io/docs/reference/access-authn-authz/authentication/#anonymous-requests
anonymousAuthentication:
healthEndpoints:
allowed: true
otherEndpoints:
allowed: true

View File

@@ -1,4 +1,4 @@
# Copyright 2020-2021 the Pinniped contributors. All Rights Reserved.
# Copyright 2020-2026 the Pinniped contributors. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
# The name of the cluster type.
@@ -13,9 +13,13 @@ capabilities:
# Will the cluster successfully provision a load balancer if requested?
hasExternalLoadBalancerProvider: true
# Does the cluster allow requests without authentication?
# https://kubernetes.io/docs/reference/access-authn-authz/authentication/#anonymous-requests
anonymousAuthenticationSupported: true
# Are LDAP ports on the Internet reachable without interference from network firewalls or proxies?
canReachInternetLDAPPorts: true
# Does the cluster allow requests without authentication?
# https://kubernetes.io/docs/reference/access-authn-authz/authentication/#anonymous-requests
anonymousAuthentication:
healthEndpoints:
allowed: true
otherEndpoints:
allowed: true

View File

@@ -1,4 +1,4 @@
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2026 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package integration
@@ -218,7 +218,7 @@ func TestCredentialRequest_Browser(t *testing.T) {
// for its localhost listener via --listen-port=env.CLIUpstreamOIDC.CallbackURL.Port() per oidcLoginCommand.
// Since ports are global to the process, tests using oidcLoginCommand must be run serially.
func TestCredentialRequest_JWTAuthenticatorRulesToDisallowLogin_Browser(t *testing.T) {
env := testlib.IntegrationEnv(t).WithCapability(testlib.AnonymousAuthenticationSupported)
env := testlib.IntegrationEnv(t).WithCapability(testlib.AnonymousAuthenticationSupportedForOtherEndpoints)
basicSpec := &authenticationv1alpha1.JWTAuthenticatorSpec{
Issuer: env.CLIUpstreamOIDC.Issuer,
@@ -321,7 +321,7 @@ func TestCredentialRequest_JWTAuthenticatorRulesToDisallowLogin_Browser(t *testi
// TCRs are non-mutating and safe to run in parallel with serial tests, see main_test.go.
func TestCredentialRequest_ShouldFailWhenTheAuthenticatorDoesNotExist_Parallel(t *testing.T) {
env := testlib.IntegrationEnv(t).WithCapability(testlib.AnonymousAuthenticationSupported)
env := testlib.IntegrationEnv(t).WithCapability(testlib.AnonymousAuthenticationSupportedForOtherEndpoints)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
t.Cleanup(cancel)
@@ -344,7 +344,7 @@ func TestCredentialRequest_ShouldFailWhenTheAuthenticatorDoesNotExist_Parallel(t
// TCRs are non-mutating and safe to run in parallel with serial tests, see main_test.go.
func TestCredentialRequest_ShouldFailWhenTheRequestIsValidButTheTokenDoesNotAuthenticateTheUser_Parallel(t *testing.T) {
env := testlib.IntegrationEnv(t).WithCapability(testlib.AnonymousAuthenticationSupported)
env := testlib.IntegrationEnv(t).WithCapability(testlib.AnonymousAuthenticationSupportedForOtherEndpoints)
// Create a testWebhook so we have a legitimate authenticator to pass to the TokenCredentialRequest API.
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
@@ -365,7 +365,7 @@ func TestCredentialRequest_ShouldFailWhenTheRequestIsValidButTheTokenDoesNotAuth
// TCRs are non-mutating and safe to run in parallel with serial tests, see main_test.go.
func TestCredentialRequest_ShouldFailWhenRequestDoesNotIncludeToken_Parallel(t *testing.T) {
env := testlib.IntegrationEnv(t).WithCapability(testlib.AnonymousAuthenticationSupported)
env := testlib.IntegrationEnv(t).WithCapability(testlib.AnonymousAuthenticationSupportedForOtherEndpoints)
// Create a testWebhook so we have a legitimate authenticator to pass to the TokenCredentialRequest API.
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)

View File

@@ -1,4 +1,4 @@
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2026 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package integration
@@ -902,8 +902,8 @@ func TestImpersonationProxy(t *testing.T) { //nolint:gocyclo // yeah, it's compl
whoAmI, err = impersonationProxyAnonymousPinnipedConciergeClient.IdentityV1alpha1().WhoAmIRequests().
Create(ctx, &identityv1alpha1.WhoAmIRequest{}, metav1.CreateOptions{})
// we expect the impersonation proxy to match the behavior of KAS in regards to anonymous requests
if env.HasCapability(testlib.AnonymousAuthenticationSupported) {
// we expect the impersonation proxy to match the behavior of KAS in regard to anonymous requests
if env.HasCapability(testlib.AnonymousAuthenticationSupportedForOtherEndpoints) {
require.NoError(t, err, testlib.Sdump(err))
require.Equal(t,
expectedWhoAmIRequestResponse(
@@ -1409,8 +1409,8 @@ func TestImpersonationProxy(t *testing.T) { //nolint:gocyclo // yeah, it's compl
})
})
t.Run("anonymous authentication enabled", func(t *testing.T) {
testlib.IntegrationEnv(t).WithCapability(testlib.AnonymousAuthenticationSupported)
t.Run("anonymous authentication enabled for health checks", func(t *testing.T) {
testlib.IntegrationEnv(t).WithCapability(testlib.AnonymousAuthenticationSupportedForHealthEndpoints)
parallelIfNotEKS(t)
// anonymous auth enabled
@@ -1421,11 +1421,50 @@ func TestImpersonationProxy(t *testing.T) { //nolint:gocyclo // yeah, it's compl
t.Run("non-resource request", func(t *testing.T) {
parallelIfNotEKS(t)
healthz, errHealth := impersonationProxyAnonymousRestClient.Get().AbsPath("/healthz").DoRaw(ctx)
require.NoError(t, errHealth, testlib.Sdump(errHealth))
require.Equal(t, "ok", string(healthz))
})
response, err := impersonationProxyAnonymousRestClient.Get().AbsPath("/healthz").DoRaw(ctx)
require.NoError(t, err, testlib.Sdump(err))
require.Equal(t, "ok", string(response))
response, err = impersonationProxyAnonymousRestClient.Get().AbsPath("/readyz").DoRaw(ctx)
require.NoError(t, err, testlib.Sdump(err))
require.Equal(t, "ok", string(response))
response, err = impersonationProxyAnonymousRestClient.Get().AbsPath("/livez").DoRaw(ctx)
require.NoError(t, err, testlib.Sdump(err))
require.Equal(t, "ok", string(response))
})
})
t.Run("anonymous authentication disabled for health checks", func(t *testing.T) {
testlib.IntegrationEnv(t).WithoutCapability(testlib.AnonymousAuthenticationSupportedForHealthEndpoints)
parallelIfNotEKS(t)
// anonymous auth disabled
// - hit the healthz endpoint (non-resource endpoint)
// - through the impersonation proxy
// - should fail Unauthorized
t.Run("non-resource request", func(t *testing.T) {
parallelIfNotEKS(t)
expectedResponse := `{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Unauthorized","reason":"Unauthorized","code":401}` + "\n"
response, err := impersonationProxyAnonymousRestClient.Get().AbsPath("/healthz").DoRaw(ctx)
require.True(t, apierrors.IsUnauthorized(err), testlib.Sdump(err))
require.Equal(t, expectedResponse, string(response))
response, err = impersonationProxyAnonymousRestClient.Get().AbsPath("/readyz").DoRaw(ctx)
require.True(t, apierrors.IsUnauthorized(err), testlib.Sdump(err))
require.Equal(t, expectedResponse, string(response))
response, err = impersonationProxyAnonymousRestClient.Get().AbsPath("/livez").DoRaw(ctx)
require.True(t, apierrors.IsUnauthorized(err), testlib.Sdump(err))
require.Equal(t, expectedResponse, string(response))
})
})
t.Run("anonymous authentication enabled for other endpoints", func(t *testing.T) {
testlib.IntegrationEnv(t).WithCapability(testlib.AnonymousAuthenticationSupportedForOtherEndpoints)
parallelIfNotEKS(t)
// - hit the pods endpoint (a resource endpoint)
// - through the impersonation proxy
// - should fail forbidden
@@ -1462,22 +1501,10 @@ func TestImpersonationProxy(t *testing.T) { //nolint:gocyclo // yeah, it's compl
})
})
t.Run("anonymous authentication disabled", func(t *testing.T) {
testlib.IntegrationEnv(t).WithoutCapability(testlib.AnonymousAuthenticationSupported)
t.Run("anonymous authentication disabled for other endpoints", func(t *testing.T) {
testlib.IntegrationEnv(t).WithoutCapability(testlib.AnonymousAuthenticationSupportedForOtherEndpoints)
parallelIfNotEKS(t)
// - hit the healthz endpoint (non-resource endpoint)
// - through the impersonation proxy
// - should fail unauthorized
// - kube api server should reject it
t.Run("non-resource request", func(t *testing.T) {
parallelIfNotEKS(t)
healthz, err := impersonationProxyAnonymousRestClient.Get().AbsPath("/healthz").DoRaw(ctx)
require.True(t, apierrors.IsUnauthorized(err), testlib.Sdump(err))
require.Equal(t, `{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Failure","message":"Unauthorized","reason":"Unauthorized","code":401}`+"\n", string(healthz))
})
// - hit the pods endpoint (a resource endpoint)
// - through the impersonation proxy
// - should fail unauthorized
@@ -1491,7 +1518,7 @@ func TestImpersonationProxy(t *testing.T) { //nolint:gocyclo // yeah, it's compl
require.Equal(t, &corev1.Pod{}, pod)
})
// - request to whoami (pinniped resource endpoing)
// - request to whoami (pinniped resource endpoint)
// - through the impersonation proxy
// - should fail unauthorized
// - kube api server should reject it
@@ -1982,7 +2009,7 @@ func TestImpersonationProxy(t *testing.T) { //nolint:gocyclo // yeah, it's compl
// include an unsuccessful impersonation strategy saying that it was manually configured to be disabled.
requireDisabledStrategy(ctx, t, env, adminConciergeClient)
if !env.HasCapability(testlib.ClusterSigningKeyIsAvailable) && env.HasCapability(testlib.AnonymousAuthenticationSupported) {
if !env.HasCapability(testlib.ClusterSigningKeyIsAvailable) && env.HasCapability(testlib.AnonymousAuthenticationSupportedForOtherEndpoints) {
// This cluster does not support the cluster signing key strategy, so now that we've manually disabled the
// impersonation strategy, we should be left with no working strategies.
// Given that there are no working strategies, a TokenCredentialRequest which would otherwise work should now

View File

@@ -1,4 +1,4 @@
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2026 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package integration
@@ -394,7 +394,7 @@ func maybeNeedsExtraWithSHA256(
// whoami requests are non-mutating and safe to run in parallel with serial tests, see main_test.go.
func TestWhoAmI_Anonymous_Parallel(t *testing.T) {
_ = testlib.IntegrationEnv(t).WithCapability(testlib.AnonymousAuthenticationSupported)
_ = testlib.IntegrationEnv(t).WithCapability(testlib.AnonymousAuthenticationSupportedForOtherEndpoints)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()

View File

@@ -1,4 +1,4 @@
// Copyright 2022-2025 the Pinniped contributors. All Rights Reserved.
// Copyright 2022-2026 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package integration
@@ -1040,11 +1040,11 @@ func TestOIDCClientSecretRequestUnauthenticated_Parallel(t *testing.T) {
}, metav1.CreateOptions{})
require.Error(t, err)
if env.KubernetesDistribution == testlib.AKSDistro {
// On AKS the error just says "Unauthorized".
require.Contains(t, err.Error(), "Unauthorized")
} else {
if env.HasCapability(testlib.AnonymousAuthenticationSupportedForOtherEndpoints) {
// Clusters which allow anonymous auth will give a more detailed error.
require.Contains(t, err.Error(), `User "system:anonymous" cannot create resource "oidcclientsecretrequests"`)
} else {
// On AKS and any other cluster which disallows anonymous auth, the error just says "Unauthorized".
require.Contains(t, err.Error(), "Unauthorized")
}
}

View File

@@ -1,4 +1,4 @@
// Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
// Copyright 2020-2026 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package testlib
@@ -9,6 +9,7 @@ import (
"net/url"
"os"
"sort"
"strconv"
"strings"
"sync"
"testing"
@@ -17,16 +18,18 @@ import (
"sigs.k8s.io/yaml"
authenticationv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/authentication/v1alpha1"
"go.pinniped.dev/internal/testutil"
)
type Capability string
type KubeDistro string
const (
ClusterSigningKeyIsAvailable Capability = "clusterSigningKeyIsAvailable"
AnonymousAuthenticationSupported Capability = "anonymousAuthenticationSupported"
HasExternalLoadBalancerProvider Capability = "hasExternalLoadBalancerProvider"
CanReachInternetLDAPPorts Capability = "canReachInternetLDAPPorts"
ClusterSigningKeyIsAvailable Capability = "clusterSigningKeyIsAvailable"
HasExternalLoadBalancerProvider Capability = "hasExternalLoadBalancerProvider"
CanReachInternetLDAPPorts Capability = "canReachInternetLDAPPorts"
AnonymousAuthenticationSupportedForHealthEndpoints Capability = "anonymousAuthenticationSupportedForHealthEndpoints"
AnonymousAuthenticationSupportedForOtherEndpoints Capability = "anonymousAuthenticationSupportedForOtherEndpoints"
KindDistro KubeDistro = "Kind"
GKEDistro KubeDistro = "GKE"
@@ -35,6 +38,24 @@ const (
TKGSDistro KubeDistro = "TKGS"
)
type Capabilities struct {
ClusterSigningKeyIsAvailable bool `json:"clusterSigningKeyIsAvailable"`
HasExternalLoadBalancerProvider bool `json:"hasExternalLoadBalancerProvider"`
CanReachInternetLDAPPorts bool `json:"canReachInternetLDAPPorts"`
AnonymousAuthentication AnonymousAuthenticationCapabilities `json:"anonymousAuthentication"`
}
type AnonymousAuthenticationCapabilities struct {
HealthEndpoints AnonymousAuthenticationEndpointCapability `json:"healthEndpoints"`
OtherEndpoints AnonymousAuthenticationEndpointCapability `json:"otherEndpoints"`
}
type AnonymousAuthenticationEndpointCapability struct {
Allowed bool `json:"allowed"`
AllowedIfK8sMinorVersionLessThan string `json:"allowedIfK8sMinorVersionLessThan"`
}
// TestEnv captures all the external parameters consumed by our integration tests.
type TestEnv struct {
t *testing.T
@@ -50,7 +71,7 @@ type TestEnv struct {
SupervisorCustomLabels map[string]string `json:"supervisorCustomLabels"`
ConciergeCustomLabels map[string]string `json:"conciergeCustomLabels"`
KubernetesDistribution KubeDistro `json:"kubernetesDistribution"`
Capabilities map[Capability]bool `json:"capabilities"`
Capabilities Capabilities `json:"capabilities"`
TestWebhook authenticationv1alpha1.WebhookAuthenticatorSpec `json:"testWebhook"`
SupervisorHTTPSAddress string `json:"supervisorHttpsAddress"`
SupervisorHTTPSIngressAddress string `json:"supervisorHttpsIngressAddress"`
@@ -400,9 +421,34 @@ func loadEnvVars(t *testing.T, result *TestEnv) {
func (e *TestEnv) HasCapability(cap Capability) bool {
e.t.Helper()
isCapable, capabilityWasDescribed := e.Capabilities[cap]
require.Truef(e.t, capabilityWasDescribed, "the %q capability of the test environment was not described", cap)
return isCapable
switch cap {
case AnonymousAuthenticationSupportedForHealthEndpoints:
versionLessThan := e.Capabilities.AnonymousAuthentication.HealthEndpoints.AllowedIfK8sMinorVersionLessThan
if versionLessThan == "" {
return e.Capabilities.AnonymousAuthentication.HealthEndpoints.Allowed
}
minorVersionNumber, err := strconv.Atoi(versionLessThan)
require.NoError(e.t, err, "could not parse minor version number from AnonymousAuthentication HealthEndpoints capability as int")
return !testutil.KubeServerMinorVersionAtLeastInclusive(e.t, NewKubernetesClientset(e.t).Discovery(), minorVersionNumber)
case AnonymousAuthenticationSupportedForOtherEndpoints:
versionLessThan := e.Capabilities.AnonymousAuthentication.OtherEndpoints.AllowedIfK8sMinorVersionLessThan
if versionLessThan == "" {
return e.Capabilities.AnonymousAuthentication.OtherEndpoints.Allowed
}
minorVersionNumber, err := strconv.Atoi(versionLessThan)
require.NoError(e.t, err, "could not parse minor version number from AnonymousAuthentication OtherEndpoints capability as int")
return !testutil.KubeServerMinorVersionAtLeastInclusive(e.t, NewKubernetesClientset(e.t).Discovery(), minorVersionNumber)
case ClusterSigningKeyIsAvailable:
return e.Capabilities.ClusterSigningKeyIsAvailable
case HasExternalLoadBalancerProvider:
return e.Capabilities.HasExternalLoadBalancerProvider
case CanReachInternetLDAPPorts:
return e.Capabilities.CanReachInternetLDAPPorts
default:
require.Failf(e.t, "unknown capability type", "name: %s", cap)
return false
}
}
func (e *TestEnv) WithCapability(cap Capability) *TestEnv {