Compare commits

...

108 Commits

Author SHA1 Message Date
Hidetake Iwata
fb00b17088 Configure automatically generated release notes (#1222) 2025-01-08 09:17:45 +09:00
renovate[bot]
c836641412 fix(deps): update module golang.org/x/term to v0.28.0 (#1220)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-05 05:07:45 +00:00
renovate[bot]
d471ea7152 fix(deps): update module golang.org/x/oauth2 to v0.25.0 (#1219)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-04 17:06:05 +00:00
renovate[bot]
33d94678d6 fix(deps): update module github.com/coreos/go-oidc/v3 to v3.12.0 (#1218)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-04 08:09:46 +00:00
renovate[bot]
9f9ec16196 fix(deps): update module github.com/golangci/golangci-lint to v1.63.4 (#1217)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-04 00:39:06 +00:00
renovate[bot]
10e957702d fix(deps): update module github.com/vektra/mockery/v2 to v2.50.4 (#1216)
* fix(deps): update module github.com/vektra/mockery/v2 to v2.50.4

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/12603054218

* Empty commit to trigger GitHub Actions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: int128-renovate-merge-bot[bot] <132176788+int128-renovate-merge-bot[bot]@users.noreply.github.com>
2025-01-03 22:07:25 +00:00
renovate[bot]
b7a90a5a5c fix(deps): update module github.com/golangci/golangci-lint to v1.63.3 (#1215)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-03 00:40:06 +00:00
renovate[bot]
f852891af3 fix(deps): update module github.com/golangci/golangci-lint to v1.63.2 (#1214)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-02 17:07:10 +00:00
renovate[bot]
994a063566 fix(deps): update module github.com/vektra/mockery/v2 to v2.50.3 (#1213)
* fix(deps): update module github.com/vektra/mockery/v2 to v2.50.3

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/12577746109

* Empty commit to trigger GitHub Actions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: int128-renovate-merge-bot[bot] <132176788+int128-renovate-merge-bot[bot]@users.noreply.github.com>
2025-01-02 06:11:54 +00:00
renovate[bot]
7aa20d770c fix(deps): update module github.com/golangci/golangci-lint to v1.63.1 (#1212)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-02 00:18:32 +00:00
renovate[bot]
9806833dfe fix(deps): update module github.com/golangci/golangci-lint to v1.63.0 (#1211)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-01 17:07:04 +00:00
renovate[bot]
a6ce0d461e fix(deps): update module github.com/vektra/mockery/v2 to v2.50.2 (#1209)
* fix(deps): update module github.com/vektra/mockery/v2 to v2.50.2

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/12554219550

* Empty commit to trigger GitHub Actions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: int128-renovate-merge-bot[bot] <132176788+int128-renovate-merge-bot[bot]@users.noreply.github.com>
2024-12-31 03:12:19 +00:00
Hidetake Iwata
97b0a20b0b Remove deprecated --listen-port flag (#1207) 2024-12-27 15:22:53 +09:00
renovate[bot]
97fc59829b fix(deps): update module github.com/vektra/mockery/v2 to v2.50.1 (#1206)
* fix(deps): update module github.com/vektra/mockery/v2 to v2.50.1

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/12478246181

* Empty commit to trigger GitHub Actions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: int128-renovate-merge-bot[bot] <132176788+int128-renovate-merge-bot[bot]@users.noreply.github.com>
2024-12-24 08:11:17 +00:00
renovate[bot]
d5df561b9d chore(deps): update docker/setup-buildx-action action to v3.8.0 (#1205)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-16 14:08:50 +00:00
renovate[bot]
750675fd8f fix(deps): update kubernetes packages to v0.32.0 (#1204)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-12 02:21:14 +00:00
renovate[bot]
2d9b849a1f chore(deps): update actions/setup-go action to v5.2.0 (#1203)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-11 09:09:31 +00:00
renovate[bot]
4f584cd504 fix(deps): update kubernetes packages to v0.31.4 (#1202)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-11 03:26:40 +00:00
renovate[bot]
ec2be992e9 chore(deps): update int128/docker-build-cache-config-action action to v1.37.0 (#1201)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-08 12:14:46 +00:00
renovate[bot]
8c62d95679 fix(deps): update module github.com/vektra/mockery/v2 to v2.50.0 (#1199)
* fix(deps): update module github.com/vektra/mockery/v2 to v2.50.0

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/12164768589

* Empty commit to trigger GitHub Actions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: int128-renovate-merge-bot[bot] <132176788+int128-renovate-merge-bot[bot]@users.noreply.github.com>
2024-12-04 20:10:07 +00:00
renovate[bot]
b643d5fcaf fix(deps): update module golang.org/x/term to v0.27.0 (#1200)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-04 18:12:11 +00:00
renovate[bot]
6c064ccd87 chore(deps): update dependency go to v1.23.4 (#1197)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-04 17:07:57 +00:00
renovate[bot]
d0f250d13d fix(deps): update module golang.org/x/sync to v0.10.0 (#1198)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-04 15:30:27 +00:00
renovate[bot]
fd1ed4c971 fix(deps): update module github.com/vektra/mockery/v2 to v2.49.2 (#1196)
* fix(deps): update module github.com/vektra/mockery/v2 to v2.49.2

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/12145201435

* Empty commit to trigger GitHub Actions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: int128-renovate-merge-bot[bot] <132176788+int128-renovate-merge-bot[bot]@users.noreply.github.com>
2024-12-03 20:10:09 +00:00
renovate[bot]
7fc9dfddd4 fix(deps): update module github.com/vektra/mockery/v2 to v2.49.1 (#1194)
* fix(deps): update module github.com/vektra/mockery/v2 to v2.49.1

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/12042258621

* Empty commit to trigger GitHub Actions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: int128-renovate-merge-bot[bot] <132176788+int128-renovate-merge-bot[bot]@users.noreply.github.com>
2024-11-27 03:25:18 +00:00
renovate[bot]
54d5a58a00 chore(deps): update docker/build-push-action action to v6.10.0 (#1193)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-26 17:08:01 +00:00
renovate[bot]
9af4c6af05 fix(deps): update module github.com/golangci/golangci-lint to v1.62.2 (#1192)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 16:10:26 +00:00
renovate[bot]
e3a7e80907 fix(deps): update module github.com/stretchr/testify to v1.10.0 (#1191)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-23 14:07:09 +00:00
renovate[bot]
7f2bcb653e fix(deps): update kubernetes packages to v0.31.3 (#1190)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-21 09:09:10 +00:00
renovate[bot]
0164b3ef69 fix(deps): update module github.com/vektra/mockery/v2 to v2.49.0 (#1189)
* fix(deps): update module github.com/vektra/mockery/v2 to v2.49.0

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/11945541249

* Empty commit to trigger GitHub Actions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: int128-renovate-merge-bot[bot] <132176788+int128-renovate-merge-bot[bot]@users.noreply.github.com>
2024-11-21 05:08:48 +00:00
renovate[bot]
3d31e81128 chore(deps): update docker/metadata-action action to v5.6.1 (#1188)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-19 20:09:39 +00:00
renovate[bot]
fc1767f1d0 chore(deps): update docker/metadata-action action to v5.6.0 (#1187)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-19 18:11:34 +00:00
renovate[bot]
4ae812342e fix(deps): update module github.com/vektra/mockery/v2 to v2.48.0 (#1186)
* fix(deps): update module github.com/vektra/mockery/v2 to v2.48.0

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/11910966209

* Empty commit to trigger GitHub Actions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: int128-renovate-merge-bot[bot] <132176788+int128-renovate-merge-bot[bot]@users.noreply.github.com>
2024-11-19 12:15:53 +00:00
renovate[bot]
f1367689a8 chore(deps): update int128/update-generated-files-action action to v2.56.0 (#1185)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-15 17:07:37 +00:00
renovate[bot]
ea88241e34 chore(deps): update int128/docker-build-cache-config-action action to v1.36.0 (#1184)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-15 12:15:38 +00:00
renovate[bot]
ebda978f02 fix(deps): update module github.com/vektra/mockery/v2 to v2.47.0 (#1183)
* fix(deps): update module github.com/vektra/mockery/v2 to v2.47.0

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/11844880778

* Empty commit to trigger GitHub Actions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: int128-renovate-merge-bot[bot] <132176788+int128-renovate-merge-bot[bot]@users.noreply.github.com>
2024-11-14 22:07:46 +00:00
renovate[bot]
d03f57bdbd fix(deps): update module github.com/chromedp/chromedp to v0.11.2 (#1181)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-11 12:15:16 +00:00
renovate[bot]
cc0318db18 fix(deps): update module github.com/golangci/golangci-lint to v1.62.0 (#1180)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-10 21:31:21 +00:00
renovate[bot]
f8fabda051 chore(deps): update rajatjindal/krew-release-bot action to v0.0.47 (#1179)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-10 20:08:11 +00:00
Hidetake Iwata
43922b3b43 Use BUILDPLATFORM for multi-architecture build (#1178)
* Refactor docker build workflows

* Refactor
2024-11-10 16:49:05 +09:00
renovate[bot]
ada466d3a7 chore(deps): update dependency int128/go-renovate-config to v1.7.2 (#1165)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-10 10:49:14 +09:00
Hidetake Iwata
df0eae3497 Refactor go workflows (#1176)
* Refactor go workflows

* Fix
2024-11-10 10:46:47 +09:00
renovate[bot]
239b93925c fix(deps): update module github.com/int128/oauth2cli to v1.14.1 (#1175)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-09 15:08:24 +00:00
renovate[bot]
17ac028bd7 fix(deps): update module golang.org/x/oauth2 to v0.24.0 (#1167)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-08 06:11:37 +00:00
renovate[bot]
946fde9567 fix(deps): update module golang.org/x/term to v0.26.0 (#1169)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-08 05:08:09 +00:00
Hidetake Iwata
ad727ee576 Add links to OIDC spec or RFC (#1172) 2024-11-08 11:28:19 +09:00
Hidetake Iwata
a87beb33b6 Use Go 1.22 router (integration_test) (#1171) 2024-11-08 10:47:27 +09:00
Hidetake Iwata
5d657ed981 Extract service package (integration_test) (#1170)
* Extract service package (integration_test)

* Refactor

* make generate

* Rename

* Comment

* Refactor
2024-11-08 10:20:20 +09:00
renovate[bot]
b69f00f380 chore(deps): update dependency go to v1.23.3 (#1166)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-08 00:46:40 +00:00
renovate[bot]
fdbd391a92 fix(deps): update module golang.org/x/sync to v0.9.0 (#1168)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-08 00:38:55 +00:00
Hidetake Iwata
1895099836 Fix flaky system test (#1164) 2024-11-03 18:08:46 +09:00
Hidetake Iwata
0e9a39a571 Infer apiVersion from KUBERNETES_EXEC_INFO environment variable (#1162)
* Infer apiVersion from KUBERNETES_EXEC_INFO

* Test client.authentication.k8s.io/v1

* Set --exec-interactive-mode

* Set --exec-interactive-mode=Never

* Fix comments
2024-11-03 17:21:25 +09:00
Hidetake Iwata
f1f2a37adc Include essential options to token cache key (#1161) 2024-10-26 21:42:23 +09:00
Hidetake Iwata
438068e9de refactor: Move useAccessToken to oidc.Provider (#1160)
* refactor: Move useAccessToken to oidc.Provider

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/11530911738

---------

Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
2024-10-26 21:07:44 +09:00
renovate[bot]
aaf9a6a58f chore(deps): update dependency int128/go-renovate-config to v1.6.1 (#1149)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-26 18:26:49 +09:00
renovate[bot]
9567ab157b fix(deps): update kubernetes packages to v0.31.2 (#1159)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-23 18:08:57 +00:00
renovate[bot]
f49d73087a fix(deps): update module github.com/chromedp/chromedp to v0.11.1 (#1158)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-23 05:08:53 +00:00
renovate[bot]
1c84d270a9 fix(deps): update module github.com/chromedp/chromedp to v0.11.0 (#1157)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-14 21:45:14 +00:00
renovate[bot]
1b245f9947 fix(deps): update module github.com/vektra/mockery/v2 to v2.46.3 (#1156)
* fix(deps): update module github.com/vektra/mockery/v2 to v2.46.3

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/11320535114

* Empty commit to trigger GitHub Actions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: int128-renovate-merge-bot[bot] <132176788+int128-renovate-merge-bot[bot]@users.noreply.github.com>
2024-10-14 06:12:32 +00:00
renovate[bot]
963942afad fix(deps): update module golang.org/x/term to v0.25.0 (#1155)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-04 18:10:39 +00:00
renovate[bot]
24357b6ea7 chore(deps): update dependency go to v1.23.2 (#1153)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-02 20:09:23 +00:00
renovate[bot]
4e7a44cdbe fix(deps): update module github.com/vektra/mockery/v2 to v2.46.2 (#1154)
* fix(deps): update module github.com/vektra/mockery/v2 to v2.46.2

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/11147159678

* Empty commit to trigger GitHub Actions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: int128-renovate-merge-bot[bot] <132176788+int128-renovate-merge-bot[bot]@users.noreply.github.com>
2024-10-02 18:11:24 +00:00
renovate[bot]
3f7513754c fix(deps): update module github.com/vektra/mockery/v2 to v2.46.1 (#1152)
* fix(deps): update module github.com/vektra/mockery/v2 to v2.46.1

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/11081139611

* Empty commit to trigger GitHub Actions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: int128-renovate-merge-bot[bot] <132176788+int128-renovate-merge-bot[bot]@users.noreply.github.com>
2024-09-28 06:10:30 +00:00
renovate[bot]
61555d8ee2 chore(deps): update dependency go to v1.23.1 (#1148)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-24 15:19:54 +09:00
Hidetake Iwata
f22f6ee483 Update go directive in go.mod (#1147) 2024-09-24 15:11:20 +09:00
Hidetake Iwata
c2cbc47438 Lock dedicated file instead of token cache file (#1146)
* Run test on Windows

* Run integration_test on Windows and macOS

* Lock dedicated file instead of token cache file

* Add comment
2024-09-24 14:39:53 +09:00
Hidetake Iwata
765d97542c Use go-version-file (#1142) 2024-09-23 18:06:11 +09:00
Hidetake Iwata
3d114bfeba Lock token cache file before authentication (#1126)
* Lock token cache file in authentication

* Fix tests

* make generate

* Lock before FindByKey

* Fix test
2024-09-21 14:54:32 +09:00
renovate[bot]
f0c3628f2a fix(deps): update module github.com/vektra/mockery/v2 to v2.46.0 (#1141)
* fix(deps): update module github.com/vektra/mockery/v2 to v2.46.0

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/10896389638

* Empty commit to trigger GitHub Actions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: int128-renovate-merge-bot[bot] <132176788+int128-renovate-merge-bot[bot]@users.noreply.github.com>
2024-09-17 06:11:39 +00:00
renovate[bot]
57f5409402 fix(deps): update kubernetes packages to v0.31.1 (#1140)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-12 09:08:10 +00:00
renovate[bot]
1601ba1ef1 chore(deps): update dependency golangci/golangci-lint to v1.61.0 (#1139)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-09 21:37:37 +00:00
renovate[bot]
7c733fe841 fix(deps): update module github.com/vektra/mockery/v2 to v2.45.1 (#1138)
* fix(deps): update module github.com/vektra/mockery/v2 to v2.45.1

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/10779024006

* Empty commit to trigger GitHub Actions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: int128-renovate-merge-bot[bot] <132176788+int128-renovate-merge-bot[bot]@users.noreply.github.com>
2024-09-09 20:08:32 +00:00
renovate[bot]
244c32b5d7 fix(deps): update module golang.org/x/oauth2 to v0.23.0 (#1134)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-05 23:08:15 +00:00
renovate[bot]
2bbff2c363 chore(deps): update dependency golang-version to v1.23.1 (#1137)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-05 21:07:02 +00:00
renovate[bot]
3c5c326a2a fix(deps): update module golang.org/x/term to v0.24.0 (#1135)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-04 17:06:53 +00:00
renovate[bot]
cabd0e7c2f fix(deps): update module github.com/vektra/mockery/v2 to v2.45.0 (#1131)
* fix(deps): update module github.com/vektra/mockery/v2 to v2.45.0

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/10554564162

* Empty commit to trigger GitHub Actions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: int128-renovate-merge-bot[bot] <132176788+int128-renovate-merge-bot[bot]@users.noreply.github.com>
2024-08-26 08:11:25 +00:00
renovate[bot]
cf9f86b386 fix(deps): update module github.com/vektra/mockery/v2 to v2.44.2 (#1125)
* fix(deps): update module github.com/vektra/mockery/v2 to v2.44.2

* Generated by GitHub Actions (go / generate)

https://github.com/int128/kubelogin/actions/runs/10437019943

* Empty commit to trigger GitHub Actions

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: int128-renovate-merge-bot[bot] <132176788+int128-renovate-merge-bot[bot]@users.noreply.github.com>
2024-08-26 06:11:21 +00:00
renovate[bot]
e3a43015c3 chore(deps): update dependency golangci/golangci-lint to v1.60.3 (#1130)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-23 03:24:12 +00:00
renovate[bot]
17b1ef093f chore(deps): update dependency golangci/golangci-lint to v1.60.2 (#1128)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-21 01:24:56 +00:00
Hidetake Iwata
b1c8a18c76 Add wire to make generate (#1127) 2024-08-18 11:10:49 +09:00
Hidetake Iwata
66127ff3fc Migrate to mockery packages feature (#1124)
* Migrate to mockery packages feature

* Fix workflow
2024-08-17 12:27:13 +09:00
Hidetake Iwata
1b267eb7af Update flags in usage.md (#1123) 2024-08-16 17:07:48 +09:00
renovate[bot]
a49bd30178 fix(deps): update module gopkg.in/yaml.v2 to v3 (#845)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-16 17:01:57 +09:00
Adam Kafka
905238ce07 Add new --oidc-use-access-token flag to get-token (#1084)
* Add new `--oidc-use-access-token` flag to `get-token`

Implements https://github.com/int128/kubelogin/issues/1083. See
description there for context.

In its current form, this PR is bare bones functionality. I have not yet
added any tests to confirm this behavior. Additionally, we could
consider updtating some of the naming. It is confusing to return a
`TokenSet` where `IDToken` actually has an `accessToken`. I'm open to
feedback on how best to improve this.

However, this PR is functional. I have validated it locally. Without
adding `--oidc-use-access-token`, and `id_token` is successfully
returned. Adding `--oidc-use-access-token` results in an `access_token`
being successfully returned.

* Fix failing tests

Needed to plumb through our new parameter `UseAccessToken` to the mocks
as well.

* Add a test to make sure new flag is plumbed through

* Support Access Tokens whose audience differ from the client_id

As noted in the PR, there are some cases where the access token `aud`
field will not be the `client_id`. To allow for these, we use a
different token verifier that will not verify that claim.

---------

Co-authored-by: Adam kafka <akafka@tesla.com>
2024-08-16 16:57:05 +09:00
renovate[bot]
70ce255a8d fix(deps): update kubernetes packages to v0.31.0 (#1120)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-14 17:27:51 +00:00
renovate[bot]
0e4865fbec chore(deps): update golang docker tag to v1.23 (#1121)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-14 14:48:00 +00:00
renovate[bot]
1e44ca40f8 chore(deps): update dependency golang-version to v1.23.0 (#1119)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-14 11:04:47 +00:00
renovate[bot]
394175ef87 chore(deps): update dependency golangci/golangci-lint to v1.60.1 (#1122)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-14 08:14:03 +00:00
renovate[bot]
20e4e62ee9 fix(deps): update module golang.org/x/term to v0.23.0 (#1117)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-07 01:54:08 +00:00
renovate[bot]
fae1341887 chore(deps): update dependency golang-version to v1.22.6 (#1116)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-06 22:29:33 +00:00
renovate[bot]
878a3e5d18 fix(deps): update module golang.org/x/sync to v0.8.0 (#1115)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-05 02:18:53 +00:00
renovate[bot]
192daaa938 fix(deps): update module golang.org/x/oauth2 to v0.22.0 (#1114)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-04 21:44:19 +00:00
Hidetake Iwata
a2f4e935dc Remove golang.org/x/net/context (#1112) 2024-08-03 11:42:54 +09:00
renovate[bot]
98531a75c3 fix(deps): update module github.com/chromedp/chromedp to v0.10.0 (#1111)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-02 01:03:00 +00:00
renovate[bot]
fef0f2d73b fix(deps): update kubernetes packages to v0.30.3 (#1108)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-18 04:51:42 +00:00
renovate[bot]
8c9aea0662 fix(deps): update module github.com/coreos/go-oidc/v3 to v3.11.0 (#1107)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-08 22:50:06 +00:00
renovate[bot]
d878ace92c fix(deps): update module golang.org/x/net to v0.27.0 (#1106)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-05 18:57:17 +00:00
renovate[bot]
7424e8c09e chore(deps): update dependency golang-version to v1.22.5 (#1104)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-05 01:02:42 +00:00
renovate[bot]
1989395c30 fix(deps): update module golang.org/x/term to v0.22.0 (#1105)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-04 22:29:50 +00:00
renovate[bot]
51c45683ce fix(deps): update module k8s.io/klog/v2 to v2.130.1 (#1102)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-30 14:12:54 +00:00
renovate[bot]
0edac231c7 fix(deps): update module github.com/spf13/cobra to v1.8.1 (#1101)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-30 09:02:24 +00:00
renovate[bot]
646449cdd5 fix(deps): update kubernetes packages to v0.30.2 (#1100)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-30 07:29:24 +00:00
Hidetake Iwata
38e1dec3df Update dexidp/dex to v2.39.0 (#1103) 2024-06-30 13:53:12 +09:00
renovate[bot]
717f1a668b chore(deps): update dependency golangci/golangci-lint to v1.59.1 (#1099)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-09 21:02:29 +00:00
renovate[bot]
baf1b6419c fix(deps): update module golang.org/x/net to v0.26.0 (#1098)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-05 04:38:22 +00:00
renovate[bot]
9b86200fca chore(deps): update dependency golang-version to v1.22.4 (#1097)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-05 01:56:14 +00:00
renovate[bot]
380ab4090c fix(deps): update module golang.org/x/term to v0.21.0 (#1096)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-04 22:11:20 +00:00
renovate[bot]
fcbb25dd1b fix(deps): update module golang.org/x/oauth2 to v0.21.0 (#1095)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-04 18:08:42 +00:00
92 changed files with 4400 additions and 1938 deletions

16
.github/release.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
# https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes
changelog:
categories:
- title: Features
labels:
- '*'
exclude:
labels:
- renovate
- refactoring
- title: Refactoring
labels:
- refactoring
- title: Dependencies
labels:
- renovate

View File

@@ -2,9 +2,11 @@
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"github>int128/renovate-base",
"github>int128/go-renovate-config",
"github>int128/go-renovate-config:github-actions",
"github>int128/go-renovate-config:kubernetes",
"github>int128/go-renovate-config:kustomization-github-releases",
"github>int128/go-renovate-config#v1.7.2",
"github>int128/go-renovate-config:go-directive#v1.7.2",
"github>int128/go-renovate-config:github-actions#v1.7.2",
"github>int128/go-renovate-config:kubernetes#v1.7.2",
"github>int128/go-renovate-config:kustomization-github-releases#v1.7.2",
"helpers:pinGitHubActionDigests",
],
}

View File

@@ -9,7 +9,6 @@ on:
- pkg/**
- go.*
- Dockerfile
- Makefile
push:
branches:
- master
@@ -18,59 +17,53 @@ on:
- pkg/**
- go.*
- Dockerfile
- Makefile
tags:
- v*
jobs:
build-linux-amd64:
uses: int128/docker-build-workflow/.github/workflows/build.yaml@v1
with:
platforms: linux/amd64
flavor: latest=false,suffix=-linux-amd64
build-linux-arm64:
uses: int128/docker-build-workflow/.github/workflows/build.yaml@v1
with:
platforms: linux/arm64
flavor: latest=false,suffix=-linux-arm64
build-linux-ppc64le:
uses: int128/docker-build-workflow/.github/workflows/build.yaml@v1
with:
platforms: linux/ppc64le
flavor: latest=false,suffix=-linux-ppc64le
build:
needs:
- build-linux-amd64
- build-linux-arm64
- build-linux-ppc64le
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
packages: write
outputs:
image-uri: ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}
steps:
- uses: docker/login-action@v3
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/metadata-action@v5
- uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 # v5.6.1
id: metadata
with:
images: ghcr.io/${{ github.repository }}
- uses: int128/docker-manifest-create-action@v2
- uses: int128/docker-build-cache-config-action@622932dfa73db7d3a65e40d5fcc094f2101e659a # v1.37.0
id: cache
with:
image: ghcr.io/${{ github.repository }}/cache
- uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0
- uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
- uses: docker/build-push-action@48aba3b46d1b1fec4febb7c5d0c644b249a11355 # v6.10.0
id: build
with:
push: true
tags: ${{ steps.metadata.outputs.tags }}
sources: |
ghcr.io/${{ github.repository }}@${{ needs.build-linux-amd64.outputs.digest }}
ghcr.io/${{ github.repository }}@${{ needs.build-linux-arm64.outputs.digest }}
ghcr.io/${{ github.repository }}@${{ needs.build-linux-ppc64le.outputs.digest }}
labels: ${{ steps.metadata.outputs.labels }}
cache-from: ${{ steps.cache.outputs.cache-from }}
cache-to: ${{ steps.cache.outputs.cache-to }}
platforms: |
linux/amd64
linux/arm64
linux/ppc64le
test:
needs: build
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- run: docker run --rm '${{ needs.build.outputs.image-uri }}' --help
- run: docker run --rm "$IMAGE_URI" --help
env:
IMAGE_URI: ${{ needs.build.outputs.image-uri }}

View File

@@ -7,7 +7,10 @@ on:
paths:
- .github/workflows/go.yaml
- pkg/**
- go.*
- integration_test/**
- mocks/**
- tools/**
- '**/go.*'
tags:
- v*
pull_request:
@@ -16,21 +19,61 @@ on:
paths:
- .github/workflows/go.yaml
- pkg/**
- go.*
- integration_test/**
- mocks/**
- tools/**
- '**/go.*'
jobs:
check:
uses: int128/go-workflows/.github/workflows/check.yaml@v0.3.0
with:
go-version: 1.22.3
golangci-lint-version: v1.59.0
test:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
with:
go-version: 1.22.3
- run: go test -v -race ./...
go-version-file: go.mod
cache-dependency-path: go.sum
- run: make test
integration-test:
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest
- macos-latest
- windows-latest
runs-on: ${{ matrix.os }}
timeout-minutes: 10
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
with:
go-version-file: go.mod
cache-dependency-path: go.sum
- run: make integration-test
lint:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
with:
go-version-file: tools/go.mod
cache-dependency-path: tools/go.sum
- run: make lint
generate:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
with:
go-version-file: tools/go.mod
cache-dependency-path: tools/go.sum
- run: go mod tidy
- run: make generate
- uses: int128/update-generated-files-action@7eb71af1ae8e30d970ea5512d23fd2f4b0eae44c # v2.56.0

View File

@@ -54,12 +54,13 @@ jobs:
CGO_ENABLED: ${{ matrix.platform.CGO_ENABLED }}
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
with:
go-version: 1.22.3
go-version-file: go.mod
cache-dependency-path: go.sum
- run: go build -ldflags '-X main.version=${{ github.ref_name }}'
- uses: int128/go-release-action@v2
- uses: int128/go-release-action@2979cc5b15ceb7ae458e95b0a9467afc7ae25259 # v2.0.0
with:
binary: kubelogin
@@ -70,5 +71,5 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: rajatjindal/krew-release-bot@v0.0.46
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: rajatjindal/krew-release-bot@3d9faef30a82761d610544f62afddca00993eef9 # v0.0.47

View File

@@ -22,10 +22,11 @@ jobs:
system-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
with:
go-version: 1.22.3
go-version-file: go.mod
cache-dependency-path: go.sum
# for certutil
# https://packages.ubuntu.com/xenial/libnss3-tools

2
.gitignore vendored
View File

@@ -1,5 +1,7 @@
/.idea
/tools/bin
/acceptance_test/output/
/coverage.out

11
.mockery.yaml Normal file
View File

@@ -0,0 +1,11 @@
outpkg: "{{.PackageName}}_mock"
dir: "mocks/{{.PackagePath}}_mock"
packages:
github.com/int128/kubelogin:
config:
all: true
recursive: true
io:
interfaces:
Closer:

View File

@@ -1,11 +1,19 @@
FROM golang:1.22 as builder
FROM --platform=$BUILDPLATFORM golang:1.23 AS builder
WORKDIR /builder
COPY go.* .
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
RUN go mod download
# Copy the go source
COPY main.go .
COPY pkg pkg
RUN go build
ARG TARGETOS
ARG TARGETARCH
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build
FROM gcr.io/distroless/base-debian12
COPY --from=builder /builder/kubelogin /

22
Makefile Normal file
View File

@@ -0,0 +1,22 @@
.PHONY: all
all:
.PHONY: test
test:
go test -v -race ./pkg/...
.PHONY: integration-test
integration-test:
go test -v -race ./integration_test/...
.PHONY: generate
generate:
$(MAKE) -C tools
./tools/bin/wire ./pkg/di
rm -fr mocks/
./tools/bin/mockery
.PHONY: lint
lint:
$(MAKE) -C tools
./tools/bin/golangci-lint run

View File

@@ -12,6 +12,7 @@ Flags:
--oidc-client-secret string Client secret of the provider
--oidc-extra-scope strings Scopes to request to the provider
--oidc-use-pkce Force PKCE usage
--oidc-use-access-token Instead of using the id_token, use the access_token to authenticate to Kubernetes
--token-cache-dir string Path to a directory for token cache (default "~/.kube/cache/oidc-login")
--force-refresh If set, refresh the ID token regardless of its expiration time
--certificate-authority stringArray Path to a cert file for the certificate authority
@@ -36,16 +37,16 @@ Flags:
Global Flags:
--add_dir_header If true, adds the file directory to the header of the log messages
--alsologtostderr log to standard error as well as files
--alsologtostderr log to standard error as well as files (no effect when -logtostderr=true)
--log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0)
--log_dir string If non-empty, write log files in this directory
--log_file string If non-empty, use this log file
--log_file_max_size uint Defines the maximum size a log file can grow to. Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800)
--log_dir string If non-empty, write log files in this directory (no effect when -logtostderr=true)
--log_file string If non-empty, use this log file (no effect when -logtostderr=true)
--log_file_max_size uint Defines the maximum size a log file can grow to (no effect when -logtostderr=true). Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800)
--logtostderr log to standard error instead of files (default true)
--one_output If true, only write logs to their native severity level (vs also writing to each lower severity level)
--one_output If true, only write logs to their native severity level (vs also writing to each lower severity level; no effect when -logtostderr=true)
--skip_headers If true, avoid header prefixes in the log messages
--skip_log_headers If true, avoid headers when opening log files
--stderrthreshold severity logs at or above this threshold go to stderr (default 2)
--skip_log_headers If true, avoid headers when opening log files (no effect when -logtostderr=true)
--stderrthreshold severity logs at or above this threshold go to stderr when writing to files and stderr (no effect when -logtostderr=true or -alsologtostderr=true) (default 2)
-v, --v Level number for the log level verbosity
--vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
```

67
go.mod
View File

@@ -1,59 +1,62 @@
module github.com/int128/kubelogin
go 1.22.2
go 1.23.4
require (
github.com/alexflint/go-filemutex v1.3.0
github.com/chromedp/chromedp v0.9.5
github.com/coreos/go-oidc/v3 v3.10.0
github.com/chromedp/chromedp v0.11.2
github.com/coreos/go-oidc/v3 v3.12.0
github.com/gofrs/flock v0.12.1
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/google/go-cmp v0.6.0
github.com/google/wire v0.6.0
github.com/int128/oauth2cli v1.14.0
github.com/int128/oauth2cli v1.14.1
github.com/int128/oauth2dev v1.0.1
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
github.com/spf13/cobra v1.8.0
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.9.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.20.0
gopkg.in/yaml.v2 v2.4.0
k8s.io/apimachinery v0.30.1
k8s.io/client-go v0.30.1
k8s.io/klog/v2 v2.120.1
github.com/stretchr/testify v1.10.0
golang.org/x/oauth2 v0.25.0
golang.org/x/sync v0.10.0
golang.org/x/term v0.28.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/apimachinery v0.32.0
k8s.io/client-go v0.32.0
k8s.io/klog/v2 v2.130.1
)
require (
github.com/chromedp/cdproto v0.0.0-20240202021202-6d0b6a386732 // indirect
github.com/chromedp/sysutil v1.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-jose/go-jose/v4 v4.0.1 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/chromedp/cdproto v0.0.0-20241022234722-4d5d5faf59fb // indirect
github.com/chromedp/sysutil v1.1.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.3.2 // indirect
github.com/gobwas/ws v1.4.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/imdario/mergo v0.3.6 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/int128/listener v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/stretchr/objx v0.5.2 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
golang.org/x/time v0.3.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
golang.org/x/crypto v0.28.0 // indirect
golang.org/x/net v0.30.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/text v0.19.0 // indirect
golang.org/x/time v0.7.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)

495
go.sum
View File

@@ -1,175 +1,78 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/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=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/alexflint/go-filemutex v1.3.0 h1:LgE+nTUWnQCyRKbpoceKZsPQbs84LivvgwUymZXdOcM=
github.com/alexflint/go-filemutex v1.3.0/go.mod h1:U0+VA/i30mGBlLCrFPGtTe9y6wGQfNAWPBTekHQ+c8A=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chromedp/cdproto v0.0.0-20240202021202-6d0b6a386732 h1:XYUCaZrW8ckGWlCRJKCSoh/iFwlpX316a8yY9IFEzv8=
github.com/chromedp/cdproto v0.0.0-20240202021202-6d0b6a386732/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=
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/coreos/go-oidc/v3 v3.10.0 h1:tDnXHnLyiTVyT/2zLDGj09pFPkhND8Gl8lnTRhoEaJU=
github.com/coreos/go-oidc/v3 v3.10.0/go.mod h1:5j11xcw0D3+SGxn6Z/WFADsgcWVMyNAlSQupk0KK3ac=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
github.com/chromedp/cdproto v0.0.0-20241022234722-4d5d5faf59fb h1:noKVm2SsG4v0Yd0lHNtFYc9EUxIVvrr4kJ6hM8wvIYU=
github.com/chromedp/cdproto v0.0.0-20241022234722-4d5d5faf59fb/go.mod h1:4XqMl3iIW08jtieURWL6Tt5924w21pxirC6th662XUM=
github.com/chromedp/chromedp v0.11.2 h1:ZRHTh7DjbNTlfIv3NFTbB7eVeu5XCNkgrpcGSpn2oX0=
github.com/chromedp/chromedp v0.11.2/go.mod h1:lr8dFRLKsdTTWb75C/Ttol2vnBKOSnt0BW8R9Xaupi8=
github.com/chromedp/sysutil v1.1.0 h1:PUFNv5EcprjqXZD9nJb9b/c9ibAbxiYo4exNWZyipwM=
github.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHGPTUfWTJ8=
github.com/coreos/go-oidc/v3 v3.12.0 h1:sJk+8G2qq94rDI6ehZ71Bol3oUHy63qNYmkiSjrc/Jo=
github.com/coreos/go-oidc/v3 v3.12.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U=
github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/go-jose/go-jose/v4 v4.0.2 h1:R3l3kkBds16bO7ZFAEEcofK0MkrAJt3jlJznWZG0nvk=
github.com/go-jose/go-jose/v4 v4.0.2/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.3.2 h1:zlnbNHxumkRvfPWgfXu8RBwyNR1x8wh9cf5PTOCqs9Q=
github.com/gobwas/ws v1.3.2/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs=
github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc=
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.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/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=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/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=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI=
github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/int128/listener v1.1.0 h1:2Jb41DWLpkQ3I9bIdBzO8H/tNwMvyl/OBZWtCV5Pjuw=
github.com/int128/listener v1.1.0/go.mod h1:68WkmTN8PQtLzc9DucIaagAKeGVyMnyyKIkW4Xn47UA=
github.com/int128/oauth2cli v1.14.0 h1:r63NoO10ybUXIXUQxih8WOmt5HQpJubdTmhWh22B9VE=
github.com/int128/oauth2cli v1.14.0/go.mod h1:LIoVAzgAsS2tDDBc8yopkcgY5oZR0+MJAeECkCwtxhA=
github.com/int128/oauth2cli v1.14.1 h1:MxkiSSMT1RcsVKxyzaJYGgmMXvGWPXTMduhG4a1OqTs=
github.com/int128/oauth2cli v1.14.1/go.mod h1:ha/eC3cUAixVzJ0V+voMRNQejLWGvk49AWDWN4Gawsk=
github.com/int128/oauth2dev v1.0.1 h1:TWokv4obxKuRZXvcXFMOYcaAcdZ/rcZYcbjkJNu+6Ek=
github.com/int128/oauth2dev v1.0.1/go.mod h1:caoxoXz7nlt2nc7/o3GKgGCyuruOAmsViPSRmrUmV9o=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
@@ -183,107 +86,48 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
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=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw=
golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.14.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=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
@@ -291,61 +135,26 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
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=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
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=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4=
golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU=
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70=
golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -354,74 +163,30 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.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/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
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/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.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.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.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=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM=
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
@@ -431,118 +196,32 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/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=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
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.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
k8s.io/api v0.30.1 h1:kCm/6mADMdbAxmIh0LBjS54nQBE+U4KmbCfIkF5CpJY=
k8s.io/api v0.30.1/go.mod h1:ddbN2C0+0DIiPntan/bye3SW3PdwLa11/0yqwvuRrJM=
k8s.io/apimachinery v0.30.1 h1:ZQStsEfo4n65yAdlGTfP/uSHMQSoYzU/oeEbkmF7P2U=
k8s.io/apimachinery v0.30.1/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
k8s.io/client-go v0.30.1 h1:uC/Ir6A3R46wdkgCV3vbLyNOYyCJ8oZnjtJGKfytl/Q=
k8s.io/client-go v0.30.1/go.mod h1:wrAqLNs2trwiCH/wxxmT/x3hKVH9PuV0GGW0oDoHVqc=
k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98=
k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/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=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
k8s.io/api v0.32.0 h1:OL9JpbvAU5ny9ga2fb24X8H6xQlVp+aJMFlgtQjR9CE=
k8s.io/api v0.32.0/go.mod h1:4LEwHZEf6Q/cG96F3dqR965sYOfmPM7rq81BLgsE0p0=
k8s.io/apimachinery v0.32.0 h1:cFSE7N3rmEEtv4ei5X6DaJPHHX0C+upp+v5lVPiEwpg=
k8s.io/apimachinery v0.32.0/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
k8s.io/client-go v0.32.0 h1:DimtMcnN/JIKZcrSrstiwvvZvLjG0aSxy8PxN8IChp8=
k8s.io/client-go v0.32.0/go.mod h1:boDWvdM1Drk4NJj/VddSLnx59X3OPgwrOo0vGbtq9+8=
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=
k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4=
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA=
sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=

View File

@@ -13,6 +13,7 @@ import (
"github.com/int128/kubelogin/integration_test/httpdriver"
"github.com/int128/kubelogin/integration_test/keypair"
"github.com/int128/kubelogin/integration_test/oidcserver"
"github.com/int128/kubelogin/integration_test/oidcserver/testconfig"
"github.com/int128/kubelogin/pkg/di"
"github.com/int128/kubelogin/pkg/infrastructure/browser"
"github.com/int128/kubelogin/pkg/testing/clock"
@@ -52,12 +53,12 @@ func TestCredentialPlugin(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
sv := oidcserver.New(t, tc.keyPair, oidcserver.Config{
Want: oidcserver.Want{
sv := oidcserver.New(t, tc.keyPair, testconfig.TestConfig{
Want: testconfig.Want{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
},
Response: oidcserver.Response{
Response: testconfig.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
@@ -77,14 +78,14 @@ func TestCredentialPlugin(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
sv := oidcserver.New(t, tc.keyPair, oidcserver.Config{
Want: oidcserver.Want{
sv := oidcserver.New(t, tc.keyPair, testconfig.TestConfig{
Want: testconfig.Want{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
Username: "USER1",
Password: "PASS1",
},
Response: oidcserver.Response{
Response: testconfig.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
@@ -107,15 +108,15 @@ func TestCredentialPlugin(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
sv := oidcserver.New(t, tc.keyPair, oidcserver.Config{})
sv := oidcserver.New(t, tc.keyPair, testconfig.TestConfig{})
t.Run("NoCache", func(t *testing.T) {
sv.SetConfig(oidcserver.Config{
Want: oidcserver.Want{
sv.SetConfig(testconfig.TestConfig{
Want: testconfig.Want{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
},
Response: oidcserver.Response{
Response: testconfig.Response{
IDTokenExpiry: now.Add(time.Hour),
RefreshToken: "REFRESH_TOKEN_1",
},
@@ -132,7 +133,7 @@ func TestCredentialPlugin(t *testing.T) {
assertCredentialPluginStdout(t, &stdout, sv.LastTokenResponse().IDToken, now.Add(time.Hour))
})
t.Run("Valid", func(t *testing.T) {
sv.SetConfig(oidcserver.Config{})
sv.SetConfig(testconfig.TestConfig{})
var stdout bytes.Buffer
runGetToken(t, ctx, getTokenConfig{
tokenCacheDir: tokenCacheDir,
@@ -145,13 +146,13 @@ func TestCredentialPlugin(t *testing.T) {
assertCredentialPluginStdout(t, &stdout, sv.LastTokenResponse().IDToken, now.Add(time.Hour))
})
t.Run("Refresh", func(t *testing.T) {
sv.SetConfig(oidcserver.Config{
Want: oidcserver.Want{
sv.SetConfig(testconfig.TestConfig{
Want: testconfig.Want{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
RefreshToken: "REFRESH_TOKEN_1",
},
Response: oidcserver.Response{
Response: testconfig.Response{
IDTokenExpiry: now.Add(3 * time.Hour),
RefreshToken: "REFRESH_TOKEN_2",
},
@@ -168,13 +169,13 @@ func TestCredentialPlugin(t *testing.T) {
assertCredentialPluginStdout(t, &stdout, sv.LastTokenResponse().IDToken, now.Add(3*time.Hour))
})
t.Run("RefreshAgain", func(t *testing.T) {
sv.SetConfig(oidcserver.Config{
Want: oidcserver.Want{
sv.SetConfig(testconfig.TestConfig{
Want: testconfig.Want{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
RefreshToken: "REFRESH_TOKEN_2",
},
Response: oidcserver.Response{
Response: testconfig.Response{
IDTokenExpiry: now.Add(5 * time.Hour),
},
})
@@ -197,13 +198,13 @@ func TestCredentialPlugin(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
sv := oidcserver.New(t, keypair.None, oidcserver.Config{
Want: oidcserver.Want{
sv := oidcserver.New(t, keypair.None, testconfig.TestConfig{
Want: testconfig.Want{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
CodeChallengeMethod: "S256",
},
Response: oidcserver.Response{
Response: testconfig.Response{
IDTokenExpiry: now.Add(time.Hour),
CodeChallengeMethodsSupported: []string{"plain", "S256"},
},
@@ -223,12 +224,12 @@ func TestCredentialPlugin(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
sv := oidcserver.New(t, keypair.Server, oidcserver.Config{
Want: oidcserver.Want{
sv := oidcserver.New(t, keypair.Server, testconfig.TestConfig{
Want: testconfig.Want{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
},
Response: oidcserver.Response{
Response: testconfig.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
@@ -248,12 +249,12 @@ func TestCredentialPlugin(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
sv := oidcserver.New(t, keypair.None, oidcserver.Config{
Want: oidcserver.Want{
sv := oidcserver.New(t, keypair.None, testconfig.TestConfig{
Want: testconfig.Want{
Scope: "email profile openid",
RedirectURIPrefix: "http://localhost:",
},
Response: oidcserver.Response{
Response: testconfig.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
@@ -276,12 +277,12 @@ func TestCredentialPlugin(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
sv := oidcserver.New(t, keypair.None, oidcserver.Config{
Want: oidcserver.Want{
sv := oidcserver.New(t, keypair.None, testconfig.TestConfig{
Want: testconfig.Want{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
},
Response: oidcserver.Response{
Response: testconfig.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
@@ -301,12 +302,12 @@ func TestCredentialPlugin(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
sv := oidcserver.New(t, keypair.None, oidcserver.Config{
Want: oidcserver.Want{
sv := oidcserver.New(t, keypair.None, testconfig.TestConfig{
Want: testconfig.Want{
Scope: "openid",
RedirectURIPrefix: "http://127.0.0.1:",
},
Response: oidcserver.Response{
Response: testconfig.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
@@ -326,12 +327,12 @@ func TestCredentialPlugin(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
sv := oidcserver.New(t, keypair.None, oidcserver.Config{
Want: oidcserver.Want{
sv := oidcserver.New(t, keypair.None, testconfig.TestConfig{
Want: testconfig.Want{
Scope: "openid",
RedirectURIPrefix: "https://localhost:",
},
Response: oidcserver.Response{
Response: testconfig.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
@@ -357,8 +358,8 @@ func TestCredentialPlugin(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
sv := oidcserver.New(t, keypair.None, oidcserver.Config{
Want: oidcserver.Want{
sv := oidcserver.New(t, keypair.None, testconfig.TestConfig{
Want: testconfig.Want{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
ExtraParams: map[string]string{
@@ -366,7 +367,7 @@ func TestCredentialPlugin(t *testing.T) {
"reauth": "false",
},
},
Response: oidcserver.Response{
Response: testconfig.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})

View File

@@ -6,7 +6,7 @@ import (
"path/filepath"
"testing"
"gopkg.in/yaml.v2"
"gopkg.in/yaml.v3"
)
// Values represents values in .kubeconfig template.

View File

@@ -1,4 +1,4 @@
// Package handler provides a HTTP handler for the OpenID Connect Provider.
// Package handler provides HTTP handlers for the OpenID Connect Provider.
package handler
import (
@@ -7,28 +7,34 @@ import (
"fmt"
"net/http"
"testing"
"github.com/int128/kubelogin/integration_test/oidcserver/service"
)
func New(t *testing.T, provider Provider) *Handler {
return &Handler{t, provider}
func Register(t *testing.T, mux *http.ServeMux, provider service.Provider) {
h := &Handlers{t, provider}
mux.HandleFunc("GET /.well-known/openid-configuration", h.Discovery)
mux.HandleFunc("GET /certs", h.GetCertificates)
mux.HandleFunc("GET /auth", h.AuthenticateCode)
mux.HandleFunc("POST /token", h.Exchange)
}
// Handler provides a HTTP handler for the OpenID Connect Provider.
// Handlers provides HTTP handlers for the OpenID Connect Provider.
// You need to implement the Provider interface.
// Note that this skips some security checks and is only for testing.
type Handler struct {
type Handlers struct {
t *testing.T
provider Provider
provider service.Provider
}
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
func (h *Handlers) handleError(w http.ResponseWriter, r *http.Request, f func() error) {
wr := &responseWriterRecorder{w, 200}
err := h.serveHTTP(wr, r)
err := f()
if err == nil {
h.t.Logf("%d %s %s", wr.statusCode, r.Method, r.RequestURI)
return
}
if errResp := new(ErrorResponse); errors.As(err, &errResp) {
if errResp := new(service.ErrorResponse); errors.As(err, &errResp) {
h.t.Logf("400 %s %s: %s", r.Method, r.RequestURI, err)
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(400)
@@ -52,28 +58,35 @@ func (w *responseWriterRecorder) WriteHeader(statusCode int) {
w.statusCode = statusCode
}
func (h *Handler) serveHTTP(w http.ResponseWriter, r *http.Request) error {
m := r.Method
p := r.URL.Path
switch {
case m == "GET" && p == "/.well-known/openid-configuration":
func (h *Handlers) Discovery(w http.ResponseWriter, r *http.Request) {
h.handleError(w, r, func() error {
discoveryResponse := h.provider.Discovery()
w.Header().Add("Content-Type", "application/json")
e := json.NewEncoder(w)
if err := e.Encode(discoveryResponse); err != nil {
return fmt.Errorf("could not render json: %w", err)
}
case m == "GET" && p == "/certs":
return nil
})
}
func (h *Handlers) GetCertificates(w http.ResponseWriter, r *http.Request) {
h.handleError(w, r, func() error {
certificatesResponse := h.provider.GetCertificates()
w.Header().Add("Content-Type", "application/json")
e := json.NewEncoder(w)
if err := e.Encode(certificatesResponse); err != nil {
return fmt.Errorf("could not render json: %w", err)
}
case m == "GET" && p == "/auth":
return nil
})
}
func (h *Handlers) AuthenticateCode(w http.ResponseWriter, r *http.Request) {
h.handleError(w, r, func() error {
q := r.URL.Query()
redirectURI, state := q.Get("redirect_uri"), q.Get("state")
code, err := h.provider.AuthenticateCode(AuthenticationRequest{
code, err := h.provider.AuthenticateCode(service.AuthenticationRequest{
RedirectURI: redirectURI,
State: state,
Scope: q.Get("scope"),
@@ -87,14 +100,19 @@ func (h *Handler) serveHTTP(w http.ResponseWriter, r *http.Request) error {
}
to := fmt.Sprintf("%s?state=%s&code=%s", redirectURI, state, code)
http.Redirect(w, r, to, 302)
case m == "POST" && p == "/token":
return nil
})
}
func (h *Handlers) Exchange(w http.ResponseWriter, r *http.Request) {
h.handleError(w, r, func() error {
if err := r.ParseForm(); err != nil {
return fmt.Errorf("could not parse the form: %w", err)
}
grantType := r.Form.Get("grant_type")
switch grantType {
case "authorization_code":
tokenResponse, err := h.provider.Exchange(TokenRequest{
tokenResponse, err := h.provider.Exchange(service.TokenRequest{
Code: r.Form.Get("code"),
CodeVerifier: r.Form.Get("code_verifier"),
})
@@ -135,13 +153,11 @@ func (h *Handler) serveHTTP(w http.ResponseWriter, r *http.Request) error {
default:
// 5.2. Error Response
// https://tools.ietf.org/html/rfc6749#section-5.2
return &ErrorResponse{
return &service.ErrorResponse{
Code: "invalid_grant",
Description: fmt.Sprintf("unknown grant_type %s", grantType),
}
}
default:
http.NotFound(w, r)
}
return nil
return nil
})
}

View File

@@ -1,74 +0,0 @@
// Package http provides a http server running on localhost for testing.
package http
import (
"context"
"net"
"net/http"
"testing"
"github.com/int128/kubelogin/integration_test/keypair"
)
func Start(t *testing.T, h http.Handler, k keypair.KeyPair) string {
if k == keypair.None {
return startNoTLS(t, h)
}
return startTLS(t, h, k)
}
func startNoTLS(t *testing.T, h http.Handler) string {
t.Helper()
l, port := newLocalhostListener(t)
url := "http://localhost:" + port
s := &http.Server{
Handler: h,
}
go func() {
err := s.Serve(l)
if err != nil && err != http.ErrServerClosed {
t.Error(err)
}
}()
t.Cleanup(func() {
if err := s.Shutdown(context.TODO()); err != nil {
t.Errorf("could not shutdown the server: %s", err)
}
})
return url
}
func startTLS(t *testing.T, h http.Handler, k keypair.KeyPair) string {
t.Helper()
l, port := newLocalhostListener(t)
url := "https://localhost:" + port
s := &http.Server{
Handler: h,
}
go func() {
err := s.ServeTLS(l, k.CertPath, k.KeyPath)
if err != nil && err != http.ErrServerClosed {
t.Error(err)
}
}()
t.Cleanup(func() {
if err := s.Shutdown(context.TODO()); err != nil {
t.Errorf("could not shutdown the server: %s", err)
}
})
return url
}
func newLocalhostListener(t *testing.T) (net.Listener, string) {
t.Helper()
l, err := net.Listen("tcp", "localhost:0")
if err != nil {
t.Fatalf("Could not create a listener: %s", err)
}
addr := l.Addr().String()
_, port, err := net.SplitHostPort(addr)
if err != nil {
t.Fatalf("Could not parse the address %s: %s", addr, err)
}
return l, port
}

View File

@@ -0,0 +1,54 @@
// Package oidcserver provides a stub of OpenID Connect provider.
package oidcserver
import (
"context"
"errors"
"fmt"
"net"
"net/http"
"net/http/httptest"
"testing"
"github.com/int128/kubelogin/integration_test/keypair"
"github.com/int128/kubelogin/integration_test/oidcserver/handler"
"github.com/int128/kubelogin/integration_test/oidcserver/service"
"github.com/int128/kubelogin/integration_test/oidcserver/testconfig"
)
// New starts a server for the OpenID Connect provider.
func New(t *testing.T, k keypair.KeyPair, c testconfig.TestConfig) service.Service {
mux := http.NewServeMux()
serverURL := startServer(t, mux, k)
svc := service.New(t, serverURL, c)
handler.Register(t, mux, svc)
return svc
}
func startServer(t *testing.T, h http.Handler, k keypair.KeyPair) string {
if k == keypair.None {
sv := httptest.NewServer(h)
t.Cleanup(sv.Close)
return sv.URL
}
// Unfortunately, httptest package did not work with keypair.KeyPair.
// We use httptest package only for allocating a new port.
portAllocator := httptest.NewUnstartedServer(h)
t.Cleanup(portAllocator.Close)
serverURL := fmt.Sprintf("https://localhost:%d", portAllocator.Listener.Addr().(*net.TCPAddr).Port)
sv := &http.Server{Handler: h}
go func() {
err := sv.ServeTLS(portAllocator.Listener, k.CertPath, k.KeyPath)
if err != nil && !errors.Is(err, http.ErrServerClosed) {
t.Error(err)
}
}()
t.Cleanup(func() {
if err := sv.Shutdown(context.TODO()); err != nil {
t.Errorf("could not shutdown the server: %s", err)
}
})
return serverURL
}

View File

@@ -1,216 +0,0 @@
// Package oidcserver provides a stub of OpenID Connect provider.
package oidcserver
import (
"crypto/sha256"
"encoding/base64"
"fmt"
"math/big"
"strings"
"testing"
"time"
"github.com/golang-jwt/jwt/v5"
"github.com/int128/kubelogin/integration_test/keypair"
"github.com/int128/kubelogin/integration_test/oidcserver/handler"
"github.com/int128/kubelogin/integration_test/oidcserver/http"
testingJWT "github.com/int128/kubelogin/pkg/testing/jwt"
)
type Server interface {
IssuerURL() string
SetConfig(Config)
LastTokenResponse() *handler.TokenResponse
}
// Want represents a set of expected values.
type Want struct {
Scope string
RedirectURIPrefix string
CodeChallengeMethod string // optional
ExtraParams map[string]string // optional
Username string // optional
Password string // optional
RefreshToken string // optional
}
// Response represents a set of response values.
type Response struct {
IDTokenExpiry time.Time
RefreshToken string
RefreshError string // if set, Refresh() will return the error
CodeChallengeMethodsSupported []string // optional
}
// Config represents a configuration of the OpenID Connect provider.
type Config struct {
Want Want
Response Response
}
// New starts a HTTP server for the OpenID Connect provider.
func New(t *testing.T, k keypair.KeyPair, c Config) Server {
sv := server{Config: c, t: t}
sv.issuerURL = http.Start(t, handler.New(t, &sv), k)
return &sv
}
type server struct {
Config
t *testing.T
issuerURL string
lastAuthenticationRequest *handler.AuthenticationRequest
lastTokenResponse *handler.TokenResponse
}
func (sv *server) IssuerURL() string {
return sv.issuerURL
}
func (sv *server) SetConfig(cfg Config) {
sv.Config = cfg
}
func (sv *server) LastTokenResponse() *handler.TokenResponse {
return sv.lastTokenResponse
}
func (sv *server) Discovery() *handler.DiscoveryResponse {
// based on https://accounts.google.com/.well-known/openid-configuration
return &handler.DiscoveryResponse{
Issuer: sv.issuerURL,
AuthorizationEndpoint: sv.issuerURL + "/auth",
TokenEndpoint: sv.issuerURL + "/token",
JwksURI: sv.issuerURL + "/certs",
UserinfoEndpoint: sv.issuerURL + "/userinfo",
RevocationEndpoint: sv.issuerURL + "/revoke",
ResponseTypesSupported: []string{"code id_token"},
SubjectTypesSupported: []string{"public"},
IDTokenSigningAlgValuesSupported: []string{"RS256"},
ScopesSupported: []string{"openid", "email", "profile"},
TokenEndpointAuthMethodsSupported: []string{"client_secret_post", "client_secret_basic"},
CodeChallengeMethodsSupported: sv.Config.Response.CodeChallengeMethodsSupported,
ClaimsSupported: []string{"aud", "email", "exp", "iat", "iss", "name", "sub"},
}
}
func (sv *server) GetCertificates() *handler.CertificatesResponse {
idTokenKeyPair := testingJWT.PrivateKey
return &handler.CertificatesResponse{
Keys: []*handler.CertificatesResponseKey{
{
Kty: "RSA",
Alg: "RS256",
Use: "sig",
Kid: "dummy",
E: base64.RawURLEncoding.EncodeToString(big.NewInt(int64(idTokenKeyPair.E)).Bytes()),
N: base64.RawURLEncoding.EncodeToString(idTokenKeyPair.N.Bytes()),
},
},
}
}
func (sv *server) AuthenticateCode(req handler.AuthenticationRequest) (code string, err error) {
if req.Scope != sv.Want.Scope {
sv.t.Errorf("scope wants `%s` but was `%s`", sv.Want.Scope, req.Scope)
}
if !strings.HasPrefix(req.RedirectURI, sv.Want.RedirectURIPrefix) {
sv.t.Errorf("redirectURI wants prefix `%s` but was `%s`", sv.Want.RedirectURIPrefix, req.RedirectURI)
}
if req.CodeChallengeMethod != sv.Want.CodeChallengeMethod {
sv.t.Errorf("code_challenge_method wants `%s` but was `%s`", sv.Want.CodeChallengeMethod, req.CodeChallengeMethod)
}
for k, v := range sv.Want.ExtraParams {
got := req.RawQuery.Get(k)
if got != v {
sv.t.Errorf("parameter %s wants `%s` but was `%s`", k, v, got)
}
}
sv.lastAuthenticationRequest = &req
return "YOUR_AUTH_CODE", nil
}
func (sv *server) Exchange(req handler.TokenRequest) (*handler.TokenResponse, error) {
if req.Code != "YOUR_AUTH_CODE" {
return nil, fmt.Errorf("code wants %s but was %s", "YOUR_AUTH_CODE", req.Code)
}
if sv.lastAuthenticationRequest.CodeChallengeMethod == "S256" {
// https://tools.ietf.org/html/rfc7636#section-4.6
challenge := computeS256Challenge(req.CodeVerifier)
if challenge != sv.lastAuthenticationRequest.CodeChallenge {
sv.t.Errorf("pkce S256 challenge did not match (want %s but was %s)", sv.lastAuthenticationRequest.CodeChallenge, challenge)
}
}
resp := &handler.TokenResponse{
TokenType: "Bearer",
ExpiresIn: 3600,
AccessToken: "YOUR_ACCESS_TOKEN",
RefreshToken: sv.Response.RefreshToken,
IDToken: testingJWT.EncodeF(sv.t, func(claims *testingJWT.Claims) {
claims.Issuer = sv.issuerURL
claims.Subject = "SUBJECT"
claims.IssuedAt = jwt.NewNumericDate(sv.Response.IDTokenExpiry.Add(-time.Hour))
claims.ExpiresAt = jwt.NewNumericDate(sv.Response.IDTokenExpiry)
claims.Audience = []string{"kubernetes"}
claims.Nonce = sv.lastAuthenticationRequest.Nonce
}),
}
sv.lastTokenResponse = resp
return resp, nil
}
func computeS256Challenge(verifier string) string {
c := sha256.Sum256([]byte(verifier))
return base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString(c[:])
}
func (sv *server) AuthenticatePassword(username, password, scope string) (*handler.TokenResponse, error) {
if scope != sv.Want.Scope {
sv.t.Errorf("scope wants `%s` but was `%s`", sv.Want.Scope, scope)
}
if username != sv.Want.Username {
sv.t.Errorf("username wants `%s` but was `%s`", sv.Want.Username, username)
}
if password != sv.Want.Password {
sv.t.Errorf("password wants `%s` but was `%s`", sv.Want.Password, password)
}
resp := &handler.TokenResponse{
TokenType: "Bearer",
ExpiresIn: 3600,
AccessToken: "YOUR_ACCESS_TOKEN",
RefreshToken: sv.Response.RefreshToken,
IDToken: testingJWT.EncodeF(sv.t, func(claims *testingJWT.Claims) {
claims.Issuer = sv.issuerURL
claims.Subject = "SUBJECT"
claims.IssuedAt = jwt.NewNumericDate(sv.Response.IDTokenExpiry.Add(-time.Hour))
claims.ExpiresAt = jwt.NewNumericDate(sv.Response.IDTokenExpiry)
claims.Audience = []string{"kubernetes"}
}),
}
sv.lastTokenResponse = resp
return resp, nil
}
func (sv *server) Refresh(refreshToken string) (*handler.TokenResponse, error) {
if refreshToken != sv.Want.RefreshToken {
sv.t.Errorf("refreshToken wants %s but was %s", sv.Want.RefreshToken, refreshToken)
}
if sv.Response.RefreshError != "" {
return nil, &handler.ErrorResponse{Code: "invalid_request", Description: sv.Response.RefreshError}
}
resp := &handler.TokenResponse{
TokenType: "Bearer",
ExpiresIn: 3600,
AccessToken: "YOUR_ACCESS_TOKEN",
RefreshToken: sv.Response.RefreshToken,
IDToken: testingJWT.EncodeF(sv.t, func(claims *testingJWT.Claims) {
claims.Issuer = sv.issuerURL
claims.Subject = "SUBJECT"
claims.IssuedAt = jwt.NewNumericDate(sv.Response.IDTokenExpiry.Add(-time.Hour))
claims.ExpiresAt = jwt.NewNumericDate(sv.Response.IDTokenExpiry)
claims.Audience = []string{"kubernetes"}
}),
}
sv.lastTokenResponse = resp
return resp, nil
}

View File

@@ -0,0 +1,183 @@
package service
import (
"crypto/sha256"
"encoding/base64"
"fmt"
"math/big"
"strings"
"testing"
"time"
"github.com/golang-jwt/jwt/v5"
"github.com/int128/kubelogin/integration_test/oidcserver/testconfig"
testingJWT "github.com/int128/kubelogin/pkg/testing/jwt"
)
func New(t *testing.T, issuerURL string, config testconfig.TestConfig) Service {
return &service{
config: config,
t: t,
issuerURL: issuerURL,
}
}
type service struct {
config testconfig.TestConfig
t *testing.T
issuerURL string
lastAuthenticationRequest *AuthenticationRequest
lastTokenResponse *TokenResponse
}
func (svc *service) IssuerURL() string {
return svc.issuerURL
}
func (svc *service) SetConfig(cfg testconfig.TestConfig) {
svc.config = cfg
}
func (svc *service) LastTokenResponse() *TokenResponse {
return svc.lastTokenResponse
}
func (svc *service) Discovery() *DiscoveryResponse {
// based on https://accounts.google.com/.well-known/openid-configuration
return &DiscoveryResponse{
Issuer: svc.issuerURL,
AuthorizationEndpoint: svc.issuerURL + "/auth",
TokenEndpoint: svc.issuerURL + "/token",
JwksURI: svc.issuerURL + "/certs",
UserinfoEndpoint: svc.issuerURL + "/userinfo",
RevocationEndpoint: svc.issuerURL + "/revoke",
ResponseTypesSupported: []string{"code id_token"},
SubjectTypesSupported: []string{"public"},
IDTokenSigningAlgValuesSupported: []string{"RS256"},
ScopesSupported: []string{"openid", "email", "profile"},
TokenEndpointAuthMethodsSupported: []string{"client_secret_post", "client_secret_basic"},
CodeChallengeMethodsSupported: svc.config.Response.CodeChallengeMethodsSupported,
ClaimsSupported: []string{"aud", "email", "exp", "iat", "iss", "name", "sub"},
}
}
func (svc *service) GetCertificates() *CertificatesResponse {
idTokenKeyPair := testingJWT.PrivateKey
return &CertificatesResponse{
Keys: []*CertificatesResponseKey{
{
Kty: "RSA",
Alg: "RS256",
Use: "sig",
Kid: "dummy",
E: base64.RawURLEncoding.EncodeToString(big.NewInt(int64(idTokenKeyPair.E)).Bytes()),
N: base64.RawURLEncoding.EncodeToString(idTokenKeyPair.N.Bytes()),
},
},
}
}
func (svc *service) AuthenticateCode(req AuthenticationRequest) (code string, err error) {
if req.Scope != svc.config.Want.Scope {
svc.t.Errorf("scope wants `%s` but was `%s`", svc.config.Want.Scope, req.Scope)
}
if !strings.HasPrefix(req.RedirectURI, svc.config.Want.RedirectURIPrefix) {
svc.t.Errorf("redirectURI wants prefix `%s` but was `%s`", svc.config.Want.RedirectURIPrefix, req.RedirectURI)
}
if req.CodeChallengeMethod != svc.config.Want.CodeChallengeMethod {
svc.t.Errorf("code_challenge_method wants `%s` but was `%s`", svc.config.Want.CodeChallengeMethod, req.CodeChallengeMethod)
}
for k, v := range svc.config.Want.ExtraParams {
got := req.RawQuery.Get(k)
if got != v {
svc.t.Errorf("parameter %s wants `%s` but was `%s`", k, v, got)
}
}
svc.lastAuthenticationRequest = &req
return "YOUR_AUTH_CODE", nil
}
func (svc *service) Exchange(req TokenRequest) (*TokenResponse, error) {
if req.Code != "YOUR_AUTH_CODE" {
return nil, fmt.Errorf("code wants %s but was %s", "YOUR_AUTH_CODE", req.Code)
}
if svc.lastAuthenticationRequest.CodeChallengeMethod == "S256" {
// https://tools.ietf.org/html/rfc7636#section-4.6
challenge := computeS256Challenge(req.CodeVerifier)
if challenge != svc.lastAuthenticationRequest.CodeChallenge {
svc.t.Errorf("pkce S256 challenge did not match (want %s but was %s)", svc.lastAuthenticationRequest.CodeChallenge, challenge)
}
}
resp := &TokenResponse{
TokenType: "Bearer",
ExpiresIn: 3600,
AccessToken: "YOUR_ACCESS_TOKEN",
RefreshToken: svc.config.Response.RefreshToken,
IDToken: testingJWT.EncodeF(svc.t, func(claims *testingJWT.Claims) {
claims.Issuer = svc.issuerURL
claims.Subject = "SUBJECT"
claims.IssuedAt = jwt.NewNumericDate(svc.config.Response.IDTokenExpiry.Add(-time.Hour))
claims.ExpiresAt = jwt.NewNumericDate(svc.config.Response.IDTokenExpiry)
claims.Audience = []string{"kubernetes"}
claims.Nonce = svc.lastAuthenticationRequest.Nonce
}),
}
svc.lastTokenResponse = resp
return resp, nil
}
func computeS256Challenge(verifier string) string {
c := sha256.Sum256([]byte(verifier))
return base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString(c[:])
}
func (svc *service) AuthenticatePassword(username, password, scope string) (*TokenResponse, error) {
if scope != svc.config.Want.Scope {
svc.t.Errorf("scope wants `%s` but was `%s`", svc.config.Want.Scope, scope)
}
if username != svc.config.Want.Username {
svc.t.Errorf("username wants `%s` but was `%s`", svc.config.Want.Username, username)
}
if password != svc.config.Want.Password {
svc.t.Errorf("password wants `%s` but was `%s`", svc.config.Want.Password, password)
}
resp := &TokenResponse{
TokenType: "Bearer",
ExpiresIn: 3600,
AccessToken: "YOUR_ACCESS_TOKEN",
RefreshToken: svc.config.Response.RefreshToken,
IDToken: testingJWT.EncodeF(svc.t, func(claims *testingJWT.Claims) {
claims.Issuer = svc.issuerURL
claims.Subject = "SUBJECT"
claims.IssuedAt = jwt.NewNumericDate(svc.config.Response.IDTokenExpiry.Add(-time.Hour))
claims.ExpiresAt = jwt.NewNumericDate(svc.config.Response.IDTokenExpiry)
claims.Audience = []string{"kubernetes"}
}),
}
svc.lastTokenResponse = resp
return resp, nil
}
func (svc *service) Refresh(refreshToken string) (*TokenResponse, error) {
if refreshToken != svc.config.Want.RefreshToken {
svc.t.Errorf("refreshToken wants %s but was %s", svc.config.Want.RefreshToken, refreshToken)
}
if svc.config.Response.RefreshError != "" {
return nil, &ErrorResponse{Code: "invalid_request", Description: svc.config.Response.RefreshError}
}
resp := &TokenResponse{
TokenType: "Bearer",
ExpiresIn: 3600,
AccessToken: "YOUR_ACCESS_TOKEN",
RefreshToken: svc.config.Response.RefreshToken,
IDToken: testingJWT.EncodeF(svc.t, func(claims *testingJWT.Claims) {
claims.Issuer = svc.issuerURL
claims.Subject = "SUBJECT"
claims.IssuedAt = jwt.NewNumericDate(svc.config.Response.IDTokenExpiry.Add(-time.Hour))
claims.ExpiresAt = jwt.NewNumericDate(svc.config.Response.IDTokenExpiry)
claims.Audience = []string{"kubernetes"}
}),
}
svc.lastTokenResponse = resp
return resp, nil
}

View File

@@ -1,11 +1,24 @@
package handler
package service
import (
"fmt"
"net/url"
"github.com/int128/kubelogin/integration_test/oidcserver/testconfig"
)
// Provider provides discovery and authentication methods.
// Service represents the test service of OpenID Connect Provider.
// It provides the feature of Provider and additional methods for testing.
type Service interface {
Provider
IssuerURL() string
SetConfig(config testconfig.TestConfig)
LastTokenResponse() *TokenResponse
}
// Provider represents an OpenID Connect Provider.
//
// If an implemented method returns an ErrorResponse,
// the handler will respond 400 and corresponding json of the ErrorResponse.
// Otherwise, the handler will respond 500 and fail the current test.
@@ -18,6 +31,8 @@ type Provider interface {
Refresh(refreshToken string) (*TokenResponse, error)
}
// DiscoveryResponse represents the type of:
// https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationResponse
type DiscoveryResponse struct {
Issuer string `json:"issuer"`
AuthorizationEndpoint string `json:"authorization_endpoint"`
@@ -34,10 +49,14 @@ type DiscoveryResponse struct {
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported"`
}
// CertificatesResponse represents the type of:
// https://datatracker.ietf.org/doc/html/rfc7517#section-5
type CertificatesResponse struct {
Keys []*CertificatesResponseKey `json:"keys"`
}
// CertificatesResponseKey represents the type of:
// https://datatracker.ietf.org/doc/html/rfc7517#section-4
type CertificatesResponseKey struct {
Kty string `json:"kty"`
Alg string `json:"alg"`
@@ -47,7 +66,7 @@ type CertificatesResponseKey struct {
E string `json:"e"`
}
// AuthenticationRequest represents a type of:
// AuthenticationRequest represents the type of:
// https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
type AuthenticationRequest struct {
RedirectURI string
@@ -59,13 +78,15 @@ type AuthenticationRequest struct {
RawQuery url.Values
}
// TokenRequest represents a type of:
// TokenRequest represents the type of:
// https://openid.net/specs/openid-connect-core-1_0.html#TokenRequest
type TokenRequest struct {
Code string
CodeVerifier string
}
// TokenResponse represents the type of:
// https://openid.net/specs/openid-connect-core-1_0.html#TokenResponse
type TokenResponse struct {
AccessToken string `json:"access_token"`
TokenType string `json:"token_type"`
@@ -74,7 +95,7 @@ type TokenResponse struct {
IDToken string `json:"id_token"`
}
// ErrorResponse represents an error response described in the following section:
// ErrorResponse represents the error response described in the following section:
// 5.2 Error Response
// https://tools.ietf.org/html/rfc6749#section-5.2
type ErrorResponse struct {

View File

@@ -0,0 +1,28 @@
package testconfig
import "time"
// Want represents a set of expected values.
type Want struct {
Scope string
RedirectURIPrefix string
CodeChallengeMethod string // optional
ExtraParams map[string]string // optional
Username string // optional
Password string // optional
RefreshToken string // optional
}
// Response represents a set of response values.
type Response struct {
IDTokenExpiry time.Time
RefreshToken string
RefreshError string // if set, Refresh() will return the error
CodeChallengeMethodsSupported []string // optional
}
// TestConfig represents a configuration of the OpenID Connect provider.
type TestConfig struct {
Want Want
Response Response
}

View File

@@ -10,6 +10,7 @@ import (
"github.com/int128/kubelogin/integration_test/keypair"
"github.com/int128/kubelogin/integration_test/kubeconfig"
"github.com/int128/kubelogin/integration_test/oidcserver"
"github.com/int128/kubelogin/integration_test/oidcserver/testconfig"
"github.com/int128/kubelogin/pkg/di"
"github.com/int128/kubelogin/pkg/infrastructure/browser"
"github.com/int128/kubelogin/pkg/testing/clock"
@@ -45,12 +46,12 @@ func TestStandalone(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
sv := oidcserver.New(t, tc.keyPair, oidcserver.Config{
Want: oidcserver.Want{
sv := oidcserver.New(t, tc.keyPair, testconfig.TestConfig{
Want: testconfig.Want{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
},
Response: oidcserver.Response{
Response: testconfig.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
@@ -74,14 +75,14 @@ func TestStandalone(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
sv := oidcserver.New(t, tc.keyPair, oidcserver.Config{
Want: oidcserver.Want{
sv := oidcserver.New(t, tc.keyPair, testconfig.TestConfig{
Want: testconfig.Want{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
Username: "USER1",
Password: "PASS1",
},
Response: oidcserver.Response{
Response: testconfig.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
@@ -109,19 +110,19 @@ func TestStandalone(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
sv := oidcserver.New(t, tc.keyPair, oidcserver.Config{})
sv := oidcserver.New(t, tc.keyPair, testconfig.TestConfig{})
kubeConfigFilename := kubeconfig.Create(t, &kubeconfig.Values{
Issuer: sv.IssuerURL(),
IDPCertificateAuthority: tc.keyPair.CACertPath,
})
t.Run("NoToken", func(t *testing.T) {
sv.SetConfig(oidcserver.Config{
Want: oidcserver.Want{
sv.SetConfig(testconfig.TestConfig{
Want: testconfig.Want{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
},
Response: oidcserver.Response{
Response: testconfig.Response{
IDTokenExpiry: now.Add(time.Hour),
RefreshToken: "REFRESH_TOKEN_1",
},
@@ -138,7 +139,7 @@ func TestStandalone(t *testing.T) {
})
})
t.Run("Valid", func(t *testing.T) {
sv.SetConfig(oidcserver.Config{})
sv.SetConfig(testconfig.TestConfig{})
runStandalone(t, ctx, standaloneConfig{
issuerURL: sv.IssuerURL(),
kubeConfigFilename: kubeConfigFilename,
@@ -151,13 +152,13 @@ func TestStandalone(t *testing.T) {
})
})
t.Run("Refresh", func(t *testing.T) {
sv.SetConfig(oidcserver.Config{
Want: oidcserver.Want{
sv.SetConfig(testconfig.TestConfig{
Want: testconfig.Want{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
RefreshToken: "REFRESH_TOKEN_1",
},
Response: oidcserver.Response{
Response: testconfig.Response{
IDTokenExpiry: now.Add(3 * time.Hour),
RefreshToken: "REFRESH_TOKEN_2",
},
@@ -174,13 +175,13 @@ func TestStandalone(t *testing.T) {
})
})
t.Run("RefreshAgain", func(t *testing.T) {
sv.SetConfig(oidcserver.Config{
Want: oidcserver.Want{
sv.SetConfig(testconfig.TestConfig{
Want: testconfig.Want{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
RefreshToken: "REFRESH_TOKEN_2",
},
Response: oidcserver.Response{
Response: testconfig.Response{
IDTokenExpiry: now.Add(5 * time.Hour),
},
})
@@ -203,12 +204,12 @@ func TestStandalone(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
sv := oidcserver.New(t, keypair.Server, oidcserver.Config{
Want: oidcserver.Want{
sv := oidcserver.New(t, keypair.Server, testconfig.TestConfig{
Want: testconfig.Want{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
},
Response: oidcserver.Response{
Response: testconfig.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
@@ -231,12 +232,12 @@ func TestStandalone(t *testing.T) {
t.Run("env_KUBECONFIG", func(t *testing.T) {
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
sv := oidcserver.New(t, keypair.None, oidcserver.Config{
Want: oidcserver.Want{
sv := oidcserver.New(t, keypair.None, testconfig.TestConfig{
Want: testconfig.Want{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
},
Response: oidcserver.Response{
Response: testconfig.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
@@ -259,12 +260,12 @@ func TestStandalone(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
sv := oidcserver.New(t, keypair.None, oidcserver.Config{
Want: oidcserver.Want{
sv := oidcserver.New(t, keypair.None, testconfig.TestConfig{
Want: testconfig.Want{
Scope: "profile groups openid",
RedirectURIPrefix: "http://localhost:",
},
Response: oidcserver.Response{
Response: testconfig.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})

View File

@@ -3,6 +3,8 @@ package main
import (
"context"
"os"
"os/signal"
"syscall"
"github.com/int128/kubelogin/pkg/di"
)
@@ -10,5 +12,8 @@ import (
var version = "HEAD"
func main() {
os.Exit(di.NewCmd().Run(context.Background(), os.Args, version))
ctx := context.Background()
ctx, stop := signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM)
defer stop()
os.Exit(di.NewCmd().Run(ctx, os.Args, version))
}

View File

@@ -0,0 +1,361 @@
// Code generated by mockery v2.50.4. DO NOT EDIT.
package service_mock
import (
service "github.com/int128/kubelogin/integration_test/oidcserver/service"
mock "github.com/stretchr/testify/mock"
)
// MockProvider is an autogenerated mock type for the Provider type
type MockProvider struct {
mock.Mock
}
type MockProvider_Expecter struct {
mock *mock.Mock
}
func (_m *MockProvider) EXPECT() *MockProvider_Expecter {
return &MockProvider_Expecter{mock: &_m.Mock}
}
// AuthenticateCode provides a mock function with given fields: req
func (_m *MockProvider) AuthenticateCode(req service.AuthenticationRequest) (string, error) {
ret := _m.Called(req)
if len(ret) == 0 {
panic("no return value specified for AuthenticateCode")
}
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func(service.AuthenticationRequest) (string, error)); ok {
return rf(req)
}
if rf, ok := ret.Get(0).(func(service.AuthenticationRequest) string); ok {
r0 = rf(req)
} else {
r0 = ret.Get(0).(string)
}
if rf, ok := ret.Get(1).(func(service.AuthenticationRequest) error); ok {
r1 = rf(req)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockProvider_AuthenticateCode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AuthenticateCode'
type MockProvider_AuthenticateCode_Call struct {
*mock.Call
}
// AuthenticateCode is a helper method to define mock.On call
// - req service.AuthenticationRequest
func (_e *MockProvider_Expecter) AuthenticateCode(req interface{}) *MockProvider_AuthenticateCode_Call {
return &MockProvider_AuthenticateCode_Call{Call: _e.mock.On("AuthenticateCode", req)}
}
func (_c *MockProvider_AuthenticateCode_Call) Run(run func(req service.AuthenticationRequest)) *MockProvider_AuthenticateCode_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(service.AuthenticationRequest))
})
return _c
}
func (_c *MockProvider_AuthenticateCode_Call) Return(code string, err error) *MockProvider_AuthenticateCode_Call {
_c.Call.Return(code, err)
return _c
}
func (_c *MockProvider_AuthenticateCode_Call) RunAndReturn(run func(service.AuthenticationRequest) (string, error)) *MockProvider_AuthenticateCode_Call {
_c.Call.Return(run)
return _c
}
// AuthenticatePassword provides a mock function with given fields: username, password, scope
func (_m *MockProvider) AuthenticatePassword(username string, password string, scope string) (*service.TokenResponse, error) {
ret := _m.Called(username, password, scope)
if len(ret) == 0 {
panic("no return value specified for AuthenticatePassword")
}
var r0 *service.TokenResponse
var r1 error
if rf, ok := ret.Get(0).(func(string, string, string) (*service.TokenResponse, error)); ok {
return rf(username, password, scope)
}
if rf, ok := ret.Get(0).(func(string, string, string) *service.TokenResponse); ok {
r0 = rf(username, password, scope)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*service.TokenResponse)
}
}
if rf, ok := ret.Get(1).(func(string, string, string) error); ok {
r1 = rf(username, password, scope)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockProvider_AuthenticatePassword_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AuthenticatePassword'
type MockProvider_AuthenticatePassword_Call struct {
*mock.Call
}
// AuthenticatePassword is a helper method to define mock.On call
// - username string
// - password string
// - scope string
func (_e *MockProvider_Expecter) AuthenticatePassword(username interface{}, password interface{}, scope interface{}) *MockProvider_AuthenticatePassword_Call {
return &MockProvider_AuthenticatePassword_Call{Call: _e.mock.On("AuthenticatePassword", username, password, scope)}
}
func (_c *MockProvider_AuthenticatePassword_Call) Run(run func(username string, password string, scope string)) *MockProvider_AuthenticatePassword_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string), args[1].(string), args[2].(string))
})
return _c
}
func (_c *MockProvider_AuthenticatePassword_Call) Return(_a0 *service.TokenResponse, _a1 error) *MockProvider_AuthenticatePassword_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockProvider_AuthenticatePassword_Call) RunAndReturn(run func(string, string, string) (*service.TokenResponse, error)) *MockProvider_AuthenticatePassword_Call {
_c.Call.Return(run)
return _c
}
// Discovery provides a mock function with no fields
func (_m *MockProvider) Discovery() *service.DiscoveryResponse {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for Discovery")
}
var r0 *service.DiscoveryResponse
if rf, ok := ret.Get(0).(func() *service.DiscoveryResponse); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*service.DiscoveryResponse)
}
}
return r0
}
// MockProvider_Discovery_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Discovery'
type MockProvider_Discovery_Call struct {
*mock.Call
}
// Discovery is a helper method to define mock.On call
func (_e *MockProvider_Expecter) Discovery() *MockProvider_Discovery_Call {
return &MockProvider_Discovery_Call{Call: _e.mock.On("Discovery")}
}
func (_c *MockProvider_Discovery_Call) Run(run func()) *MockProvider_Discovery_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *MockProvider_Discovery_Call) Return(_a0 *service.DiscoveryResponse) *MockProvider_Discovery_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockProvider_Discovery_Call) RunAndReturn(run func() *service.DiscoveryResponse) *MockProvider_Discovery_Call {
_c.Call.Return(run)
return _c
}
// Exchange provides a mock function with given fields: req
func (_m *MockProvider) Exchange(req service.TokenRequest) (*service.TokenResponse, error) {
ret := _m.Called(req)
if len(ret) == 0 {
panic("no return value specified for Exchange")
}
var r0 *service.TokenResponse
var r1 error
if rf, ok := ret.Get(0).(func(service.TokenRequest) (*service.TokenResponse, error)); ok {
return rf(req)
}
if rf, ok := ret.Get(0).(func(service.TokenRequest) *service.TokenResponse); ok {
r0 = rf(req)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*service.TokenResponse)
}
}
if rf, ok := ret.Get(1).(func(service.TokenRequest) error); ok {
r1 = rf(req)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockProvider_Exchange_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Exchange'
type MockProvider_Exchange_Call struct {
*mock.Call
}
// Exchange is a helper method to define mock.On call
// - req service.TokenRequest
func (_e *MockProvider_Expecter) Exchange(req interface{}) *MockProvider_Exchange_Call {
return &MockProvider_Exchange_Call{Call: _e.mock.On("Exchange", req)}
}
func (_c *MockProvider_Exchange_Call) Run(run func(req service.TokenRequest)) *MockProvider_Exchange_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(service.TokenRequest))
})
return _c
}
func (_c *MockProvider_Exchange_Call) Return(_a0 *service.TokenResponse, _a1 error) *MockProvider_Exchange_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockProvider_Exchange_Call) RunAndReturn(run func(service.TokenRequest) (*service.TokenResponse, error)) *MockProvider_Exchange_Call {
_c.Call.Return(run)
return _c
}
// GetCertificates provides a mock function with no fields
func (_m *MockProvider) GetCertificates() *service.CertificatesResponse {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for GetCertificates")
}
var r0 *service.CertificatesResponse
if rf, ok := ret.Get(0).(func() *service.CertificatesResponse); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*service.CertificatesResponse)
}
}
return r0
}
// MockProvider_GetCertificates_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCertificates'
type MockProvider_GetCertificates_Call struct {
*mock.Call
}
// GetCertificates is a helper method to define mock.On call
func (_e *MockProvider_Expecter) GetCertificates() *MockProvider_GetCertificates_Call {
return &MockProvider_GetCertificates_Call{Call: _e.mock.On("GetCertificates")}
}
func (_c *MockProvider_GetCertificates_Call) Run(run func()) *MockProvider_GetCertificates_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *MockProvider_GetCertificates_Call) Return(_a0 *service.CertificatesResponse) *MockProvider_GetCertificates_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockProvider_GetCertificates_Call) RunAndReturn(run func() *service.CertificatesResponse) *MockProvider_GetCertificates_Call {
_c.Call.Return(run)
return _c
}
// Refresh provides a mock function with given fields: refreshToken
func (_m *MockProvider) Refresh(refreshToken string) (*service.TokenResponse, error) {
ret := _m.Called(refreshToken)
if len(ret) == 0 {
panic("no return value specified for Refresh")
}
var r0 *service.TokenResponse
var r1 error
if rf, ok := ret.Get(0).(func(string) (*service.TokenResponse, error)); ok {
return rf(refreshToken)
}
if rf, ok := ret.Get(0).(func(string) *service.TokenResponse); ok {
r0 = rf(refreshToken)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*service.TokenResponse)
}
}
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(refreshToken)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockProvider_Refresh_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Refresh'
type MockProvider_Refresh_Call struct {
*mock.Call
}
// Refresh is a helper method to define mock.On call
// - refreshToken string
func (_e *MockProvider_Expecter) Refresh(refreshToken interface{}) *MockProvider_Refresh_Call {
return &MockProvider_Refresh_Call{Call: _e.mock.On("Refresh", refreshToken)}
}
func (_c *MockProvider_Refresh_Call) Run(run func(refreshToken string)) *MockProvider_Refresh_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string))
})
return _c
}
func (_c *MockProvider_Refresh_Call) Return(_a0 *service.TokenResponse, _a1 error) *MockProvider_Refresh_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockProvider_Refresh_Call) RunAndReturn(run func(string) (*service.TokenResponse, error)) *MockProvider_Refresh_Call {
_c.Call.Return(run)
return _c
}
// NewMockProvider creates a new instance of MockProvider. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewMockProvider(t interface {
mock.TestingT
Cleanup(func())
}) *MockProvider {
mock := &MockProvider{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@@ -0,0 +1,487 @@
// Code generated by mockery v2.50.4. DO NOT EDIT.
package service_mock
import (
service "github.com/int128/kubelogin/integration_test/oidcserver/service"
testconfig "github.com/int128/kubelogin/integration_test/oidcserver/testconfig"
mock "github.com/stretchr/testify/mock"
)
// MockService is an autogenerated mock type for the Service type
type MockService struct {
mock.Mock
}
type MockService_Expecter struct {
mock *mock.Mock
}
func (_m *MockService) EXPECT() *MockService_Expecter {
return &MockService_Expecter{mock: &_m.Mock}
}
// AuthenticateCode provides a mock function with given fields: req
func (_m *MockService) AuthenticateCode(req service.AuthenticationRequest) (string, error) {
ret := _m.Called(req)
if len(ret) == 0 {
panic("no return value specified for AuthenticateCode")
}
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func(service.AuthenticationRequest) (string, error)); ok {
return rf(req)
}
if rf, ok := ret.Get(0).(func(service.AuthenticationRequest) string); ok {
r0 = rf(req)
} else {
r0 = ret.Get(0).(string)
}
if rf, ok := ret.Get(1).(func(service.AuthenticationRequest) error); ok {
r1 = rf(req)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockService_AuthenticateCode_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AuthenticateCode'
type MockService_AuthenticateCode_Call struct {
*mock.Call
}
// AuthenticateCode is a helper method to define mock.On call
// - req service.AuthenticationRequest
func (_e *MockService_Expecter) AuthenticateCode(req interface{}) *MockService_AuthenticateCode_Call {
return &MockService_AuthenticateCode_Call{Call: _e.mock.On("AuthenticateCode", req)}
}
func (_c *MockService_AuthenticateCode_Call) Run(run func(req service.AuthenticationRequest)) *MockService_AuthenticateCode_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(service.AuthenticationRequest))
})
return _c
}
func (_c *MockService_AuthenticateCode_Call) Return(code string, err error) *MockService_AuthenticateCode_Call {
_c.Call.Return(code, err)
return _c
}
func (_c *MockService_AuthenticateCode_Call) RunAndReturn(run func(service.AuthenticationRequest) (string, error)) *MockService_AuthenticateCode_Call {
_c.Call.Return(run)
return _c
}
// AuthenticatePassword provides a mock function with given fields: username, password, scope
func (_m *MockService) AuthenticatePassword(username string, password string, scope string) (*service.TokenResponse, error) {
ret := _m.Called(username, password, scope)
if len(ret) == 0 {
panic("no return value specified for AuthenticatePassword")
}
var r0 *service.TokenResponse
var r1 error
if rf, ok := ret.Get(0).(func(string, string, string) (*service.TokenResponse, error)); ok {
return rf(username, password, scope)
}
if rf, ok := ret.Get(0).(func(string, string, string) *service.TokenResponse); ok {
r0 = rf(username, password, scope)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*service.TokenResponse)
}
}
if rf, ok := ret.Get(1).(func(string, string, string) error); ok {
r1 = rf(username, password, scope)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockService_AuthenticatePassword_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AuthenticatePassword'
type MockService_AuthenticatePassword_Call struct {
*mock.Call
}
// AuthenticatePassword is a helper method to define mock.On call
// - username string
// - password string
// - scope string
func (_e *MockService_Expecter) AuthenticatePassword(username interface{}, password interface{}, scope interface{}) *MockService_AuthenticatePassword_Call {
return &MockService_AuthenticatePassword_Call{Call: _e.mock.On("AuthenticatePassword", username, password, scope)}
}
func (_c *MockService_AuthenticatePassword_Call) Run(run func(username string, password string, scope string)) *MockService_AuthenticatePassword_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string), args[1].(string), args[2].(string))
})
return _c
}
func (_c *MockService_AuthenticatePassword_Call) Return(_a0 *service.TokenResponse, _a1 error) *MockService_AuthenticatePassword_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockService_AuthenticatePassword_Call) RunAndReturn(run func(string, string, string) (*service.TokenResponse, error)) *MockService_AuthenticatePassword_Call {
_c.Call.Return(run)
return _c
}
// Discovery provides a mock function with no fields
func (_m *MockService) Discovery() *service.DiscoveryResponse {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for Discovery")
}
var r0 *service.DiscoveryResponse
if rf, ok := ret.Get(0).(func() *service.DiscoveryResponse); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*service.DiscoveryResponse)
}
}
return r0
}
// MockService_Discovery_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Discovery'
type MockService_Discovery_Call struct {
*mock.Call
}
// Discovery is a helper method to define mock.On call
func (_e *MockService_Expecter) Discovery() *MockService_Discovery_Call {
return &MockService_Discovery_Call{Call: _e.mock.On("Discovery")}
}
func (_c *MockService_Discovery_Call) Run(run func()) *MockService_Discovery_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *MockService_Discovery_Call) Return(_a0 *service.DiscoveryResponse) *MockService_Discovery_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockService_Discovery_Call) RunAndReturn(run func() *service.DiscoveryResponse) *MockService_Discovery_Call {
_c.Call.Return(run)
return _c
}
// Exchange provides a mock function with given fields: req
func (_m *MockService) Exchange(req service.TokenRequest) (*service.TokenResponse, error) {
ret := _m.Called(req)
if len(ret) == 0 {
panic("no return value specified for Exchange")
}
var r0 *service.TokenResponse
var r1 error
if rf, ok := ret.Get(0).(func(service.TokenRequest) (*service.TokenResponse, error)); ok {
return rf(req)
}
if rf, ok := ret.Get(0).(func(service.TokenRequest) *service.TokenResponse); ok {
r0 = rf(req)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*service.TokenResponse)
}
}
if rf, ok := ret.Get(1).(func(service.TokenRequest) error); ok {
r1 = rf(req)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockService_Exchange_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Exchange'
type MockService_Exchange_Call struct {
*mock.Call
}
// Exchange is a helper method to define mock.On call
// - req service.TokenRequest
func (_e *MockService_Expecter) Exchange(req interface{}) *MockService_Exchange_Call {
return &MockService_Exchange_Call{Call: _e.mock.On("Exchange", req)}
}
func (_c *MockService_Exchange_Call) Run(run func(req service.TokenRequest)) *MockService_Exchange_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(service.TokenRequest))
})
return _c
}
func (_c *MockService_Exchange_Call) Return(_a0 *service.TokenResponse, _a1 error) *MockService_Exchange_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockService_Exchange_Call) RunAndReturn(run func(service.TokenRequest) (*service.TokenResponse, error)) *MockService_Exchange_Call {
_c.Call.Return(run)
return _c
}
// GetCertificates provides a mock function with no fields
func (_m *MockService) GetCertificates() *service.CertificatesResponse {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for GetCertificates")
}
var r0 *service.CertificatesResponse
if rf, ok := ret.Get(0).(func() *service.CertificatesResponse); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*service.CertificatesResponse)
}
}
return r0
}
// MockService_GetCertificates_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetCertificates'
type MockService_GetCertificates_Call struct {
*mock.Call
}
// GetCertificates is a helper method to define mock.On call
func (_e *MockService_Expecter) GetCertificates() *MockService_GetCertificates_Call {
return &MockService_GetCertificates_Call{Call: _e.mock.On("GetCertificates")}
}
func (_c *MockService_GetCertificates_Call) Run(run func()) *MockService_GetCertificates_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *MockService_GetCertificates_Call) Return(_a0 *service.CertificatesResponse) *MockService_GetCertificates_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockService_GetCertificates_Call) RunAndReturn(run func() *service.CertificatesResponse) *MockService_GetCertificates_Call {
_c.Call.Return(run)
return _c
}
// IssuerURL provides a mock function with no fields
func (_m *MockService) IssuerURL() string {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for IssuerURL")
}
var r0 string
if rf, ok := ret.Get(0).(func() string); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(string)
}
return r0
}
// MockService_IssuerURL_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'IssuerURL'
type MockService_IssuerURL_Call struct {
*mock.Call
}
// IssuerURL is a helper method to define mock.On call
func (_e *MockService_Expecter) IssuerURL() *MockService_IssuerURL_Call {
return &MockService_IssuerURL_Call{Call: _e.mock.On("IssuerURL")}
}
func (_c *MockService_IssuerURL_Call) Run(run func()) *MockService_IssuerURL_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *MockService_IssuerURL_Call) Return(_a0 string) *MockService_IssuerURL_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockService_IssuerURL_Call) RunAndReturn(run func() string) *MockService_IssuerURL_Call {
_c.Call.Return(run)
return _c
}
// LastTokenResponse provides a mock function with no fields
func (_m *MockService) LastTokenResponse() *service.TokenResponse {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for LastTokenResponse")
}
var r0 *service.TokenResponse
if rf, ok := ret.Get(0).(func() *service.TokenResponse); ok {
r0 = rf()
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*service.TokenResponse)
}
}
return r0
}
// MockService_LastTokenResponse_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'LastTokenResponse'
type MockService_LastTokenResponse_Call struct {
*mock.Call
}
// LastTokenResponse is a helper method to define mock.On call
func (_e *MockService_Expecter) LastTokenResponse() *MockService_LastTokenResponse_Call {
return &MockService_LastTokenResponse_Call{Call: _e.mock.On("LastTokenResponse")}
}
func (_c *MockService_LastTokenResponse_Call) Run(run func()) *MockService_LastTokenResponse_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *MockService_LastTokenResponse_Call) Return(_a0 *service.TokenResponse) *MockService_LastTokenResponse_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockService_LastTokenResponse_Call) RunAndReturn(run func() *service.TokenResponse) *MockService_LastTokenResponse_Call {
_c.Call.Return(run)
return _c
}
// Refresh provides a mock function with given fields: refreshToken
func (_m *MockService) Refresh(refreshToken string) (*service.TokenResponse, error) {
ret := _m.Called(refreshToken)
if len(ret) == 0 {
panic("no return value specified for Refresh")
}
var r0 *service.TokenResponse
var r1 error
if rf, ok := ret.Get(0).(func(string) (*service.TokenResponse, error)); ok {
return rf(refreshToken)
}
if rf, ok := ret.Get(0).(func(string) *service.TokenResponse); ok {
r0 = rf(refreshToken)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*service.TokenResponse)
}
}
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(refreshToken)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockService_Refresh_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Refresh'
type MockService_Refresh_Call struct {
*mock.Call
}
// Refresh is a helper method to define mock.On call
// - refreshToken string
func (_e *MockService_Expecter) Refresh(refreshToken interface{}) *MockService_Refresh_Call {
return &MockService_Refresh_Call{Call: _e.mock.On("Refresh", refreshToken)}
}
func (_c *MockService_Refresh_Call) Run(run func(refreshToken string)) *MockService_Refresh_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string))
})
return _c
}
func (_c *MockService_Refresh_Call) Return(_a0 *service.TokenResponse, _a1 error) *MockService_Refresh_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockService_Refresh_Call) RunAndReturn(run func(string) (*service.TokenResponse, error)) *MockService_Refresh_Call {
_c.Call.Return(run)
return _c
}
// SetConfig provides a mock function with given fields: config
func (_m *MockService) SetConfig(config testconfig.TestConfig) {
_m.Called(config)
}
// MockService_SetConfig_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SetConfig'
type MockService_SetConfig_Call struct {
*mock.Call
}
// SetConfig is a helper method to define mock.On call
// - config testconfig.TestConfig
func (_e *MockService_Expecter) SetConfig(config interface{}) *MockService_SetConfig_Call {
return &MockService_SetConfig_Call{Call: _e.mock.On("SetConfig", config)}
}
func (_c *MockService_SetConfig_Call) Run(run func(config testconfig.TestConfig)) *MockService_SetConfig_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(testconfig.TestConfig))
})
return _c
}
func (_c *MockService_SetConfig_Call) Return() *MockService_SetConfig_Call {
_c.Call.Return()
return _c
}
func (_c *MockService_SetConfig_Call) RunAndReturn(run func(testconfig.TestConfig)) *MockService_SetConfig_Call {
_c.Run(run)
return _c
}
// NewMockService creates a new instance of MockService. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewMockService(t interface {
mock.TestingT
Cleanup(func())
}) *MockService {
mock := &MockService{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@@ -1,6 +1,6 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
// Code generated by mockery v2.50.4. DO NOT EDIT.
package cmd
package cmd_mock
import (
context "context"
@@ -25,6 +25,10 @@ func (_m *MockInterface) EXPECT() *MockInterface_Expecter {
func (_m *MockInterface) Run(ctx context.Context, args []string, version string) int {
ret := _m.Called(ctx, args, version)
if len(ret) == 0 {
panic("no return value specified for Run")
}
var r0 int
if rf, ok := ret.Get(0).(func(context.Context, []string, string) int); ok {
r0 = rf(ctx, args, version)
@@ -60,13 +64,17 @@ func (_c *MockInterface_Run_Call) Return(_a0 int) *MockInterface_Run_Call {
return _c
}
type mockConstructorTestingTNewMockInterface interface {
mock.TestingT
Cleanup(func())
func (_c *MockInterface_Run_Call) RunAndReturn(run func(context.Context, []string, string) int) *MockInterface_Run_Call {
_c.Call.Return(run)
return _c
}
// NewMockInterface creates a new instance of MockInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockInterface(t mockConstructorTestingTNewMockInterface) *MockInterface {
// The first argument is typically a *testing.T value.
func NewMockInterface(t interface {
mock.TestingT
Cleanup(func())
}) *MockInterface {
mock := &MockInterface{}
mock.Mock.Test(t)

View File

@@ -0,0 +1,90 @@
// Code generated by mockery v2.50.4. DO NOT EDIT.
package reader_mock
import (
credentialplugin "github.com/int128/kubelogin/pkg/credentialplugin"
mock "github.com/stretchr/testify/mock"
)
// MockInterface is an autogenerated mock type for the Interface type
type MockInterface struct {
mock.Mock
}
type MockInterface_Expecter struct {
mock *mock.Mock
}
func (_m *MockInterface) EXPECT() *MockInterface_Expecter {
return &MockInterface_Expecter{mock: &_m.Mock}
}
// Read provides a mock function with no fields
func (_m *MockInterface) Read() (credentialplugin.Input, error) {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for Read")
}
var r0 credentialplugin.Input
var r1 error
if rf, ok := ret.Get(0).(func() (credentialplugin.Input, error)); ok {
return rf()
}
if rf, ok := ret.Get(0).(func() credentialplugin.Input); ok {
r0 = rf()
} else {
r0 = ret.Get(0).(credentialplugin.Input)
}
if rf, ok := ret.Get(1).(func() error); ok {
r1 = rf()
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockInterface_Read_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Read'
type MockInterface_Read_Call struct {
*mock.Call
}
// Read is a helper method to define mock.On call
func (_e *MockInterface_Expecter) Read() *MockInterface_Read_Call {
return &MockInterface_Read_Call{Call: _e.mock.On("Read")}
}
func (_c *MockInterface_Read_Call) Run(run func()) *MockInterface_Read_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *MockInterface_Read_Call) Return(_a0 credentialplugin.Input, _a1 error) *MockInterface_Read_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockInterface_Read_Call) RunAndReturn(run func() (credentialplugin.Input, error)) *MockInterface_Read_Call {
_c.Call.Return(run)
return _c
}
// NewMockInterface creates a new instance of MockInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewMockInterface(t interface {
mock.TestingT
Cleanup(func())
}) *MockInterface {
mock := &MockInterface{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@@ -1,6 +1,6 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
// Code generated by mockery v2.50.4. DO NOT EDIT.
package writer
package writer_mock
import (
credentialplugin "github.com/int128/kubelogin/pkg/credentialplugin"
@@ -24,6 +24,10 @@ func (_m *MockInterface) EXPECT() *MockInterface_Expecter {
func (_m *MockInterface) Write(out credentialplugin.Output) error {
ret := _m.Called(out)
if len(ret) == 0 {
panic("no return value specified for Write")
}
var r0 error
if rf, ok := ret.Get(0).(func(credentialplugin.Output) error); ok {
r0 = rf(out)
@@ -57,13 +61,17 @@ func (_c *MockInterface_Write_Call) Return(_a0 error) *MockInterface_Write_Call
return _c
}
type mockConstructorTestingTNewMockInterface interface {
mock.TestingT
Cleanup(func())
func (_c *MockInterface_Write_Call) RunAndReturn(run func(credentialplugin.Output) error) *MockInterface_Write_Call {
_c.Call.Return(run)
return _c
}
// NewMockInterface creates a new instance of MockInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockInterface(t mockConstructorTestingTNewMockInterface) *MockInterface {
// The first argument is typically a *testing.T value.
func NewMockInterface(t interface {
mock.TestingT
Cleanup(func())
}) *MockInterface {
mock := &MockInterface{}
mock.Mock.Test(t)

View File

@@ -1,6 +1,6 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
// Code generated by mockery v2.50.4. DO NOT EDIT.
package browser
package browser_mock
import (
context "context"
@@ -25,6 +25,10 @@ func (_m *MockInterface) EXPECT() *MockInterface_Expecter {
func (_m *MockInterface) Open(url string) error {
ret := _m.Called(url)
if len(ret) == 0 {
panic("no return value specified for Open")
}
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(url)
@@ -58,10 +62,19 @@ func (_c *MockInterface_Open_Call) Return(_a0 error) *MockInterface_Open_Call {
return _c
}
func (_c *MockInterface_Open_Call) RunAndReturn(run func(string) error) *MockInterface_Open_Call {
_c.Call.Return(run)
return _c
}
// OpenCommand provides a mock function with given fields: ctx, url, command
func (_m *MockInterface) OpenCommand(ctx context.Context, url string, command string) error {
ret := _m.Called(ctx, url, command)
if len(ret) == 0 {
panic("no return value specified for OpenCommand")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, string, string) error); ok {
r0 = rf(ctx, url, command)
@@ -97,13 +110,17 @@ func (_c *MockInterface_OpenCommand_Call) Return(_a0 error) *MockInterface_OpenC
return _c
}
type mockConstructorTestingTNewMockInterface interface {
mock.TestingT
Cleanup(func())
func (_c *MockInterface_OpenCommand_Call) RunAndReturn(run func(context.Context, string, string) error) *MockInterface_OpenCommand_Call {
_c.Call.Return(run)
return _c
}
// NewMockInterface creates a new instance of MockInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockInterface(t mockConstructorTestingTNewMockInterface) *MockInterface {
// The first argument is typically a *testing.T value.
func NewMockInterface(t interface {
mock.TestingT
Cleanup(func())
}) *MockInterface {
mock := &MockInterface{}
mock.Mock.Test(t)

View File

@@ -1,6 +1,6 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
// Code generated by mockery v2.50.4. DO NOT EDIT.
package clock
package clock_mock
import (
time "time"
@@ -21,10 +21,14 @@ func (_m *MockInterface) EXPECT() *MockInterface_Expecter {
return &MockInterface_Expecter{mock: &_m.Mock}
}
// Now provides a mock function with given fields:
// Now provides a mock function with no fields
func (_m *MockInterface) Now() time.Time {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for Now")
}
var r0 time.Time
if rf, ok := ret.Get(0).(func() time.Time); ok {
r0 = rf()
@@ -57,13 +61,17 @@ func (_c *MockInterface_Now_Call) Return(_a0 time.Time) *MockInterface_Now_Call
return _c
}
type mockConstructorTestingTNewMockInterface interface {
mock.TestingT
Cleanup(func())
func (_c *MockInterface_Now_Call) RunAndReturn(run func() time.Time) *MockInterface_Now_Call {
_c.Call.Return(run)
return _c
}
// NewMockInterface creates a new instance of MockInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockInterface(t mockConstructorTestingTNewMockInterface) *MockInterface {
// The first argument is typically a *testing.T value.
func NewMockInterface(t interface {
mock.TestingT
Cleanup(func())
}) *MockInterface {
mock := &MockInterface{}
mock.Mock.Test(t)

View File

@@ -1,10 +1,12 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
// Code generated by mockery v2.50.4. DO NOT EDIT.
package logger
package logger_mock
import (
pflag "github.com/spf13/pflag"
logger "github.com/int128/kubelogin/pkg/infrastructure/logger"
mock "github.com/stretchr/testify/mock"
pflag "github.com/spf13/pflag"
)
// MockInterface is an autogenerated mock type for the Interface type
@@ -48,10 +50,19 @@ func (_c *MockInterface_AddFlags_Call) Return() *MockInterface_AddFlags_Call {
return _c
}
func (_c *MockInterface_AddFlags_Call) RunAndReturn(run func(*pflag.FlagSet)) *MockInterface_AddFlags_Call {
_c.Run(run)
return _c
}
// IsEnabled provides a mock function with given fields: level
func (_m *MockInterface) IsEnabled(level int) bool {
ret := _m.Called(level)
if len(ret) == 0 {
panic("no return value specified for IsEnabled")
}
var r0 bool
if rf, ok := ret.Get(0).(func(int) bool); ok {
r0 = rf(level)
@@ -85,6 +96,11 @@ func (_c *MockInterface_IsEnabled_Call) Return(_a0 bool) *MockInterface_IsEnable
return _c
}
func (_c *MockInterface_IsEnabled_Call) RunAndReturn(run func(int) bool) *MockInterface_IsEnabled_Call {
_c.Call.Return(run)
return _c
}
// Printf provides a mock function with given fields: format, args
func (_m *MockInterface) Printf(format string, args ...interface{}) {
var _ca []interface{}
@@ -124,16 +140,25 @@ func (_c *MockInterface_Printf_Call) Return() *MockInterface_Printf_Call {
return _c
}
func (_c *MockInterface_Printf_Call) RunAndReturn(run func(string, ...interface{})) *MockInterface_Printf_Call {
_c.Run(run)
return _c
}
// V provides a mock function with given fields: level
func (_m *MockInterface) V(level int) Verbose {
func (_m *MockInterface) V(level int) logger.Verbose {
ret := _m.Called(level)
var r0 Verbose
if rf, ok := ret.Get(0).(func(int) Verbose); ok {
if len(ret) == 0 {
panic("no return value specified for V")
}
var r0 logger.Verbose
if rf, ok := ret.Get(0).(func(int) logger.Verbose); ok {
r0 = rf(level)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(Verbose)
r0 = ret.Get(0).(logger.Verbose)
}
}
@@ -158,18 +183,22 @@ func (_c *MockInterface_V_Call) Run(run func(level int)) *MockInterface_V_Call {
return _c
}
func (_c *MockInterface_V_Call) Return(_a0 Verbose) *MockInterface_V_Call {
func (_c *MockInterface_V_Call) Return(_a0 logger.Verbose) *MockInterface_V_Call {
_c.Call.Return(_a0)
return _c
}
type mockConstructorTestingTNewMockInterface interface {
mock.TestingT
Cleanup(func())
func (_c *MockInterface_V_Call) RunAndReturn(run func(int) logger.Verbose) *MockInterface_V_Call {
_c.Call.Return(run)
return _c
}
// NewMockInterface creates a new instance of MockInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockInterface(t mockConstructorTestingTNewMockInterface) *MockInterface {
// The first argument is typically a *testing.T value.
func NewMockInterface(t interface {
mock.TestingT
Cleanup(func())
}) *MockInterface {
mock := &MockInterface{}
mock.Mock.Test(t)

View File

@@ -1,6 +1,6 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
// Code generated by mockery v2.50.4. DO NOT EDIT.
package logger
package logger_mock
import mock "github.com/stretchr/testify/mock"
@@ -56,13 +56,17 @@ func (_c *MockVerbose_Infof_Call) Return() *MockVerbose_Infof_Call {
return _c
}
type mockConstructorTestingTNewMockVerbose interface {
mock.TestingT
Cleanup(func())
func (_c *MockVerbose_Infof_Call) RunAndReturn(run func(string, ...interface{})) *MockVerbose_Infof_Call {
_c.Run(run)
return _c
}
// NewMockVerbose creates a new instance of MockVerbose. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockVerbose(t mockConstructorTestingTNewMockVerbose) *MockVerbose {
// The first argument is typically a *testing.T value.
func NewMockVerbose(t interface {
mock.TestingT
Cleanup(func())
}) *MockVerbose {
mock := &MockVerbose{}
mock.Mock.Test(t)

View File

@@ -0,0 +1,76 @@
// Code generated by mockery v2.50.4. DO NOT EDIT.
package logger_mock
import mock "github.com/stretchr/testify/mock"
// MockgoLogger is an autogenerated mock type for the goLogger type
type MockgoLogger struct {
mock.Mock
}
type MockgoLogger_Expecter struct {
mock *mock.Mock
}
func (_m *MockgoLogger) EXPECT() *MockgoLogger_Expecter {
return &MockgoLogger_Expecter{mock: &_m.Mock}
}
// Printf provides a mock function with given fields: format, v
func (_m *MockgoLogger) Printf(format string, v ...interface{}) {
var _ca []interface{}
_ca = append(_ca, format)
_ca = append(_ca, v...)
_m.Called(_ca...)
}
// MockgoLogger_Printf_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Printf'
type MockgoLogger_Printf_Call struct {
*mock.Call
}
// Printf is a helper method to define mock.On call
// - format string
// - v ...interface{}
func (_e *MockgoLogger_Expecter) Printf(format interface{}, v ...interface{}) *MockgoLogger_Printf_Call {
return &MockgoLogger_Printf_Call{Call: _e.mock.On("Printf",
append([]interface{}{format}, v...)...)}
}
func (_c *MockgoLogger_Printf_Call) Run(run func(format string, v ...interface{})) *MockgoLogger_Printf_Call {
_c.Call.Run(func(args mock.Arguments) {
variadicArgs := make([]interface{}, len(args)-1)
for i, a := range args[1:] {
if a != nil {
variadicArgs[i] = a.(interface{})
}
}
run(args[0].(string), variadicArgs...)
})
return _c
}
func (_c *MockgoLogger_Printf_Call) Return() *MockgoLogger_Printf_Call {
_c.Call.Return()
return _c
}
func (_c *MockgoLogger_Printf_Call) RunAndReturn(run func(string, ...interface{})) *MockgoLogger_Printf_Call {
_c.Run(run)
return _c
}
// NewMockgoLogger creates a new instance of MockgoLogger. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewMockgoLogger(t interface {
mock.TestingT
Cleanup(func())
}) *MockgoLogger {
mock := &MockgoLogger{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@@ -1,6 +1,6 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
// Code generated by mockery v2.50.4. DO NOT EDIT.
package reader
package reader_mock
import mock "github.com/stretchr/testify/mock"
@@ -21,14 +21,21 @@ func (_m *MockInterface) EXPECT() *MockInterface_Expecter {
func (_m *MockInterface) ReadPassword(prompt string) (string, error) {
ret := _m.Called(prompt)
if len(ret) == 0 {
panic("no return value specified for ReadPassword")
}
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func(string) (string, error)); ok {
return rf(prompt)
}
if rf, ok := ret.Get(0).(func(string) string); ok {
r0 = rf(prompt)
} else {
r0 = ret.Get(0).(string)
}
var r1 error
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(prompt)
} else {
@@ -61,18 +68,30 @@ func (_c *MockInterface_ReadPassword_Call) Return(_a0 string, _a1 error) *MockIn
return _c
}
func (_c *MockInterface_ReadPassword_Call) RunAndReturn(run func(string) (string, error)) *MockInterface_ReadPassword_Call {
_c.Call.Return(run)
return _c
}
// ReadString provides a mock function with given fields: prompt
func (_m *MockInterface) ReadString(prompt string) (string, error) {
ret := _m.Called(prompt)
if len(ret) == 0 {
panic("no return value specified for ReadString")
}
var r0 string
var r1 error
if rf, ok := ret.Get(0).(func(string) (string, error)); ok {
return rf(prompt)
}
if rf, ok := ret.Get(0).(func(string) string); ok {
r0 = rf(prompt)
} else {
r0 = ret.Get(0).(string)
}
var r1 error
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(prompt)
} else {
@@ -105,13 +124,17 @@ func (_c *MockInterface_ReadString_Call) Return(_a0 string, _a1 error) *MockInte
return _c
}
type mockConstructorTestingTNewMockInterface interface {
mock.TestingT
Cleanup(func())
func (_c *MockInterface_ReadString_Call) RunAndReturn(run func(string) (string, error)) *MockInterface_ReadString_Call {
_c.Call.Return(run)
return _c
}
// NewMockInterface creates a new instance of MockInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockInterface(t mockConstructorTestingTNewMockInterface) *MockInterface {
// The first argument is typically a *testing.T value.
func NewMockInterface(t interface {
mock.TestingT
Cleanup(func())
}) *MockInterface {
mock := &MockInterface{}
mock.Mock.Test(t)

View File

@@ -0,0 +1,88 @@
// Code generated by mockery v2.50.4. DO NOT EDIT.
package stdio_mock
import mock "github.com/stretchr/testify/mock"
// MockStdin is an autogenerated mock type for the Stdin type
type MockStdin struct {
mock.Mock
}
type MockStdin_Expecter struct {
mock *mock.Mock
}
func (_m *MockStdin) EXPECT() *MockStdin_Expecter {
return &MockStdin_Expecter{mock: &_m.Mock}
}
// Read provides a mock function with given fields: p
func (_m *MockStdin) Read(p []byte) (int, error) {
ret := _m.Called(p)
if len(ret) == 0 {
panic("no return value specified for Read")
}
var r0 int
var r1 error
if rf, ok := ret.Get(0).(func([]byte) (int, error)); ok {
return rf(p)
}
if rf, ok := ret.Get(0).(func([]byte) int); ok {
r0 = rf(p)
} else {
r0 = ret.Get(0).(int)
}
if rf, ok := ret.Get(1).(func([]byte) error); ok {
r1 = rf(p)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockStdin_Read_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Read'
type MockStdin_Read_Call struct {
*mock.Call
}
// Read is a helper method to define mock.On call
// - p []byte
func (_e *MockStdin_Expecter) Read(p interface{}) *MockStdin_Read_Call {
return &MockStdin_Read_Call{Call: _e.mock.On("Read", p)}
}
func (_c *MockStdin_Read_Call) Run(run func(p []byte)) *MockStdin_Read_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].([]byte))
})
return _c
}
func (_c *MockStdin_Read_Call) Return(n int, err error) *MockStdin_Read_Call {
_c.Call.Return(n, err)
return _c
}
func (_c *MockStdin_Read_Call) RunAndReturn(run func([]byte) (int, error)) *MockStdin_Read_Call {
_c.Call.Return(run)
return _c
}
// NewMockStdin creates a new instance of MockStdin. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewMockStdin(t interface {
mock.TestingT
Cleanup(func())
}) *MockStdin {
mock := &MockStdin{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@@ -0,0 +1,88 @@
// Code generated by mockery v2.50.4. DO NOT EDIT.
package stdio_mock
import mock "github.com/stretchr/testify/mock"
// MockStdout is an autogenerated mock type for the Stdout type
type MockStdout struct {
mock.Mock
}
type MockStdout_Expecter struct {
mock *mock.Mock
}
func (_m *MockStdout) EXPECT() *MockStdout_Expecter {
return &MockStdout_Expecter{mock: &_m.Mock}
}
// Write provides a mock function with given fields: p
func (_m *MockStdout) Write(p []byte) (int, error) {
ret := _m.Called(p)
if len(ret) == 0 {
panic("no return value specified for Write")
}
var r0 int
var r1 error
if rf, ok := ret.Get(0).(func([]byte) (int, error)); ok {
return rf(p)
}
if rf, ok := ret.Get(0).(func([]byte) int); ok {
r0 = rf(p)
} else {
r0 = ret.Get(0).(int)
}
if rf, ok := ret.Get(1).(func([]byte) error); ok {
r1 = rf(p)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockStdout_Write_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Write'
type MockStdout_Write_Call struct {
*mock.Call
}
// Write is a helper method to define mock.On call
// - p []byte
func (_e *MockStdout_Expecter) Write(p interface{}) *MockStdout_Write_Call {
return &MockStdout_Write_Call{Call: _e.mock.On("Write", p)}
}
func (_c *MockStdout_Write_Call) Run(run func(p []byte)) *MockStdout_Write_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].([]byte))
})
return _c
}
func (_c *MockStdout_Write_Call) Return(n int, err error) *MockStdout_Write_Call {
_c.Call.Return(n, err)
return _c
}
func (_c *MockStdout_Write_Call) RunAndReturn(run func([]byte) (int, error)) *MockStdout_Write_Call {
_c.Call.Return(run)
return _c
}
// NewMockStdout creates a new instance of MockStdout. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewMockStdout(t interface {
mock.TestingT
Cleanup(func())
}) *MockStdout {
mock := &MockStdout{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@@ -1,6 +1,6 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
// Code generated by mockery v2.50.4. DO NOT EDIT.
package jwt
package jwt_mock
import (
time "time"
@@ -21,10 +21,14 @@ func (_m *MockClock) EXPECT() *MockClock_Expecter {
return &MockClock_Expecter{mock: &_m.Mock}
}
// Now provides a mock function with given fields:
// Now provides a mock function with no fields
func (_m *MockClock) Now() time.Time {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for Now")
}
var r0 time.Time
if rf, ok := ret.Get(0).(func() time.Time); ok {
r0 = rf()
@@ -57,13 +61,17 @@ func (_c *MockClock_Now_Call) Return(_a0 time.Time) *MockClock_Now_Call {
return _c
}
type mockConstructorTestingTNewMockClock interface {
mock.TestingT
Cleanup(func())
func (_c *MockClock_Now_Call) RunAndReturn(run func() time.Time) *MockClock_Now_Call {
_c.Call.Return(run)
return _c
}
// NewMockClock creates a new instance of MockClock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockClock(t mockConstructorTestingTNewMockClock) *MockClock {
// The first argument is typically a *testing.T value.
func NewMockClock(t interface {
mock.TestingT
Cleanup(func())
}) *MockClock {
mock := &MockClock{}
mock.Mock.Test(t)

View File

@@ -1,9 +1,10 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
// Code generated by mockery v2.50.4. DO NOT EDIT.
package loader
package loader_mock
import (
kubeconfig "github.com/int128/kubelogin/pkg/kubeconfig"
mock "github.com/stretchr/testify/mock"
)
@@ -24,7 +25,15 @@ func (_m *MockInterface) EXPECT() *MockInterface_Expecter {
func (_m *MockInterface) GetCurrentAuthProvider(explicitFilename string, contextName kubeconfig.ContextName, userName kubeconfig.UserName) (*kubeconfig.AuthProvider, error) {
ret := _m.Called(explicitFilename, contextName, userName)
if len(ret) == 0 {
panic("no return value specified for GetCurrentAuthProvider")
}
var r0 *kubeconfig.AuthProvider
var r1 error
if rf, ok := ret.Get(0).(func(string, kubeconfig.ContextName, kubeconfig.UserName) (*kubeconfig.AuthProvider, error)); ok {
return rf(explicitFilename, contextName, userName)
}
if rf, ok := ret.Get(0).(func(string, kubeconfig.ContextName, kubeconfig.UserName) *kubeconfig.AuthProvider); ok {
r0 = rf(explicitFilename, contextName, userName)
} else {
@@ -33,7 +42,6 @@ func (_m *MockInterface) GetCurrentAuthProvider(explicitFilename string, context
}
}
var r1 error
if rf, ok := ret.Get(1).(func(string, kubeconfig.ContextName, kubeconfig.UserName) error); ok {
r1 = rf(explicitFilename, contextName, userName)
} else {
@@ -68,13 +76,17 @@ func (_c *MockInterface_GetCurrentAuthProvider_Call) Return(_a0 *kubeconfig.Auth
return _c
}
type mockConstructorTestingTNewMockInterface interface {
mock.TestingT
Cleanup(func())
func (_c *MockInterface_GetCurrentAuthProvider_Call) RunAndReturn(run func(string, kubeconfig.ContextName, kubeconfig.UserName) (*kubeconfig.AuthProvider, error)) *MockInterface_GetCurrentAuthProvider_Call {
_c.Call.Return(run)
return _c
}
// NewMockInterface creates a new instance of MockInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockInterface(t mockConstructorTestingTNewMockInterface) *MockInterface {
// The first argument is typically a *testing.T value.
func NewMockInterface(t interface {
mock.TestingT
Cleanup(func())
}) *MockInterface {
mock := &MockInterface{}
mock.Mock.Test(t)

View File

@@ -1,6 +1,6 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
// Code generated by mockery v2.50.4. DO NOT EDIT.
package writer
package writer_mock
import (
kubeconfig "github.com/int128/kubelogin/pkg/kubeconfig"
@@ -24,6 +24,10 @@ func (_m *MockInterface) EXPECT() *MockInterface_Expecter {
func (_m *MockInterface) UpdateAuthProvider(p kubeconfig.AuthProvider) error {
ret := _m.Called(p)
if len(ret) == 0 {
panic("no return value specified for UpdateAuthProvider")
}
var r0 error
if rf, ok := ret.Get(0).(func(kubeconfig.AuthProvider) error); ok {
r0 = rf(p)
@@ -57,13 +61,17 @@ func (_c *MockInterface_UpdateAuthProvider_Call) Return(_a0 error) *MockInterfac
return _c
}
type mockConstructorTestingTNewMockInterface interface {
mock.TestingT
Cleanup(func())
func (_c *MockInterface_UpdateAuthProvider_Call) RunAndReturn(run func(kubeconfig.AuthProvider) error) *MockInterface_UpdateAuthProvider_Call {
_c.Call.Return(run)
return _c
}
// NewMockInterface creates a new instance of MockInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockInterface(t mockConstructorTestingTNewMockInterface) *MockInterface {
// The first argument is typically a *testing.T value.
func NewMockInterface(t interface {
mock.TestingT
Cleanup(func())
}) *MockInterface {
mock := &MockInterface{}
mock.Mock.Test(t)

View File

@@ -1,13 +1,16 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
// Code generated by mockery v2.50.4. DO NOT EDIT.
package client
package client_mock
import (
context "context"
oidc "github.com/int128/kubelogin/pkg/oidc"
client "github.com/int128/kubelogin/pkg/oidc/client"
mock "github.com/stretchr/testify/mock"
oidc "github.com/int128/kubelogin/pkg/oidc"
tlsclientconfig "github.com/int128/kubelogin/pkg/tlsclientconfig"
)
@@ -25,19 +28,26 @@ func (_m *MockFactoryInterface) EXPECT() *MockFactoryInterface_Expecter {
}
// New provides a mock function with given fields: ctx, p, tlsClientConfig
func (_m *MockFactoryInterface) New(ctx context.Context, p oidc.Provider, tlsClientConfig tlsclientconfig.Config) (Interface, error) {
func (_m *MockFactoryInterface) New(ctx context.Context, p oidc.Provider, tlsClientConfig tlsclientconfig.Config) (client.Interface, error) {
ret := _m.Called(ctx, p, tlsClientConfig)
var r0 Interface
if rf, ok := ret.Get(0).(func(context.Context, oidc.Provider, tlsclientconfig.Config) Interface); ok {
if len(ret) == 0 {
panic("no return value specified for New")
}
var r0 client.Interface
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, oidc.Provider, tlsclientconfig.Config) (client.Interface, error)); ok {
return rf(ctx, p, tlsClientConfig)
}
if rf, ok := ret.Get(0).(func(context.Context, oidc.Provider, tlsclientconfig.Config) client.Interface); ok {
r0 = rf(ctx, p, tlsClientConfig)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(Interface)
r0 = ret.Get(0).(client.Interface)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, oidc.Provider, tlsclientconfig.Config) error); ok {
r1 = rf(ctx, p, tlsClientConfig)
} else {
@@ -67,18 +77,22 @@ func (_c *MockFactoryInterface_New_Call) Run(run func(ctx context.Context, p oid
return _c
}
func (_c *MockFactoryInterface_New_Call) Return(_a0 Interface, _a1 error) *MockFactoryInterface_New_Call {
func (_c *MockFactoryInterface_New_Call) Return(_a0 client.Interface, _a1 error) *MockFactoryInterface_New_Call {
_c.Call.Return(_a0, _a1)
return _c
}
type mockConstructorTestingTNewMockFactoryInterface interface {
mock.TestingT
Cleanup(func())
func (_c *MockFactoryInterface_New_Call) RunAndReturn(run func(context.Context, oidc.Provider, tlsclientconfig.Config) (client.Interface, error)) *MockFactoryInterface_New_Call {
_c.Call.Return(run)
return _c
}
// NewMockFactoryInterface creates a new instance of MockFactoryInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockFactoryInterface(t mockConstructorTestingTNewMockFactoryInterface) *MockFactoryInterface {
// The first argument is typically a *testing.T value.
func NewMockFactoryInterface(t interface {
mock.TestingT
Cleanup(func())
}) *MockFactoryInterface {
mock := &MockFactoryInterface{}
mock.Mock.Test(t)

View File

@@ -1,13 +1,16 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
// Code generated by mockery v2.50.4. DO NOT EDIT.
package client
package client_mock
import (
context "context"
oauth2dev "github.com/int128/oauth2dev"
client "github.com/int128/kubelogin/pkg/oidc/client"
mock "github.com/stretchr/testify/mock"
oauth2dev "github.com/int128/oauth2dev"
oidc "github.com/int128/kubelogin/pkg/oidc"
)
@@ -25,11 +28,19 @@ func (_m *MockInterface) EXPECT() *MockInterface_Expecter {
}
// ExchangeAuthCode provides a mock function with given fields: ctx, in
func (_m *MockInterface) ExchangeAuthCode(ctx context.Context, in ExchangeAuthCodeInput) (*oidc.TokenSet, error) {
func (_m *MockInterface) ExchangeAuthCode(ctx context.Context, in client.ExchangeAuthCodeInput) (*oidc.TokenSet, error) {
ret := _m.Called(ctx, in)
if len(ret) == 0 {
panic("no return value specified for ExchangeAuthCode")
}
var r0 *oidc.TokenSet
if rf, ok := ret.Get(0).(func(context.Context, ExchangeAuthCodeInput) *oidc.TokenSet); ok {
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, client.ExchangeAuthCodeInput) (*oidc.TokenSet, error)); ok {
return rf(ctx, in)
}
if rf, ok := ret.Get(0).(func(context.Context, client.ExchangeAuthCodeInput) *oidc.TokenSet); ok {
r0 = rf(ctx, in)
} else {
if ret.Get(0) != nil {
@@ -37,8 +48,7 @@ func (_m *MockInterface) ExchangeAuthCode(ctx context.Context, in ExchangeAuthCo
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, ExchangeAuthCodeInput) error); ok {
if rf, ok := ret.Get(1).(func(context.Context, client.ExchangeAuthCodeInput) error); ok {
r1 = rf(ctx, in)
} else {
r1 = ret.Error(1)
@@ -54,14 +64,14 @@ type MockInterface_ExchangeAuthCode_Call struct {
// ExchangeAuthCode is a helper method to define mock.On call
// - ctx context.Context
// - in ExchangeAuthCodeInput
// - in client.ExchangeAuthCodeInput
func (_e *MockInterface_Expecter) ExchangeAuthCode(ctx interface{}, in interface{}) *MockInterface_ExchangeAuthCode_Call {
return &MockInterface_ExchangeAuthCode_Call{Call: _e.mock.On("ExchangeAuthCode", ctx, in)}
}
func (_c *MockInterface_ExchangeAuthCode_Call) Run(run func(ctx context.Context, in ExchangeAuthCodeInput)) *MockInterface_ExchangeAuthCode_Call {
func (_c *MockInterface_ExchangeAuthCode_Call) Run(run func(ctx context.Context, in client.ExchangeAuthCodeInput)) *MockInterface_ExchangeAuthCode_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(ExchangeAuthCodeInput))
run(args[0].(context.Context), args[1].(client.ExchangeAuthCodeInput))
})
return _c
}
@@ -71,11 +81,24 @@ func (_c *MockInterface_ExchangeAuthCode_Call) Return(_a0 *oidc.TokenSet, _a1 er
return _c
}
func (_c *MockInterface_ExchangeAuthCode_Call) RunAndReturn(run func(context.Context, client.ExchangeAuthCodeInput) (*oidc.TokenSet, error)) *MockInterface_ExchangeAuthCode_Call {
_c.Call.Return(run)
return _c
}
// ExchangeDeviceCode provides a mock function with given fields: ctx, authResponse
func (_m *MockInterface) ExchangeDeviceCode(ctx context.Context, authResponse *oauth2dev.AuthorizationResponse) (*oidc.TokenSet, error) {
ret := _m.Called(ctx, authResponse)
if len(ret) == 0 {
panic("no return value specified for ExchangeDeviceCode")
}
var r0 *oidc.TokenSet
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, *oauth2dev.AuthorizationResponse) (*oidc.TokenSet, error)); ok {
return rf(ctx, authResponse)
}
if rf, ok := ret.Get(0).(func(context.Context, *oauth2dev.AuthorizationResponse) *oidc.TokenSet); ok {
r0 = rf(ctx, authResponse)
} else {
@@ -84,7 +107,6 @@ func (_m *MockInterface) ExchangeDeviceCode(ctx context.Context, authResponse *o
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, *oauth2dev.AuthorizationResponse) error); ok {
r1 = rf(ctx, authResponse)
} else {
@@ -118,12 +140,21 @@ func (_c *MockInterface_ExchangeDeviceCode_Call) Return(_a0 *oidc.TokenSet, _a1
return _c
}
func (_c *MockInterface_ExchangeDeviceCode_Call) RunAndReturn(run func(context.Context, *oauth2dev.AuthorizationResponse) (*oidc.TokenSet, error)) *MockInterface_ExchangeDeviceCode_Call {
_c.Call.Return(run)
return _c
}
// GetAuthCodeURL provides a mock function with given fields: in
func (_m *MockInterface) GetAuthCodeURL(in AuthCodeURLInput) string {
func (_m *MockInterface) GetAuthCodeURL(in client.AuthCodeURLInput) string {
ret := _m.Called(in)
if len(ret) == 0 {
panic("no return value specified for GetAuthCodeURL")
}
var r0 string
if rf, ok := ret.Get(0).(func(AuthCodeURLInput) string); ok {
if rf, ok := ret.Get(0).(func(client.AuthCodeURLInput) string); ok {
r0 = rf(in)
} else {
r0 = ret.Get(0).(string)
@@ -138,14 +169,14 @@ type MockInterface_GetAuthCodeURL_Call struct {
}
// GetAuthCodeURL is a helper method to define mock.On call
// - in AuthCodeURLInput
// - in client.AuthCodeURLInput
func (_e *MockInterface_Expecter) GetAuthCodeURL(in interface{}) *MockInterface_GetAuthCodeURL_Call {
return &MockInterface_GetAuthCodeURL_Call{Call: _e.mock.On("GetAuthCodeURL", in)}
}
func (_c *MockInterface_GetAuthCodeURL_Call) Run(run func(in AuthCodeURLInput)) *MockInterface_GetAuthCodeURL_Call {
func (_c *MockInterface_GetAuthCodeURL_Call) Run(run func(in client.AuthCodeURLInput)) *MockInterface_GetAuthCodeURL_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(AuthCodeURLInput))
run(args[0].(client.AuthCodeURLInput))
})
return _c
}
@@ -155,11 +186,24 @@ func (_c *MockInterface_GetAuthCodeURL_Call) Return(_a0 string) *MockInterface_G
return _c
}
func (_c *MockInterface_GetAuthCodeURL_Call) RunAndReturn(run func(client.AuthCodeURLInput) string) *MockInterface_GetAuthCodeURL_Call {
_c.Call.Return(run)
return _c
}
// GetDeviceAuthorization provides a mock function with given fields: ctx
func (_m *MockInterface) GetDeviceAuthorization(ctx context.Context) (*oauth2dev.AuthorizationResponse, error) {
ret := _m.Called(ctx)
if len(ret) == 0 {
panic("no return value specified for GetDeviceAuthorization")
}
var r0 *oauth2dev.AuthorizationResponse
var r1 error
if rf, ok := ret.Get(0).(func(context.Context) (*oauth2dev.AuthorizationResponse, error)); ok {
return rf(ctx)
}
if rf, ok := ret.Get(0).(func(context.Context) *oauth2dev.AuthorizationResponse); ok {
r0 = rf(ctx)
} else {
@@ -168,7 +212,6 @@ func (_m *MockInterface) GetDeviceAuthorization(ctx context.Context) (*oauth2dev
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context) error); ok {
r1 = rf(ctx)
} else {
@@ -201,12 +244,25 @@ func (_c *MockInterface_GetDeviceAuthorization_Call) Return(_a0 *oauth2dev.Autho
return _c
}
func (_c *MockInterface_GetDeviceAuthorization_Call) RunAndReturn(run func(context.Context) (*oauth2dev.AuthorizationResponse, error)) *MockInterface_GetDeviceAuthorization_Call {
_c.Call.Return(run)
return _c
}
// GetTokenByAuthCode provides a mock function with given fields: ctx, in, localServerReadyChan
func (_m *MockInterface) GetTokenByAuthCode(ctx context.Context, in GetTokenByAuthCodeInput, localServerReadyChan chan<- string) (*oidc.TokenSet, error) {
func (_m *MockInterface) GetTokenByAuthCode(ctx context.Context, in client.GetTokenByAuthCodeInput, localServerReadyChan chan<- string) (*oidc.TokenSet, error) {
ret := _m.Called(ctx, in, localServerReadyChan)
if len(ret) == 0 {
panic("no return value specified for GetTokenByAuthCode")
}
var r0 *oidc.TokenSet
if rf, ok := ret.Get(0).(func(context.Context, GetTokenByAuthCodeInput, chan<- string) *oidc.TokenSet); ok {
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, client.GetTokenByAuthCodeInput, chan<- string) (*oidc.TokenSet, error)); ok {
return rf(ctx, in, localServerReadyChan)
}
if rf, ok := ret.Get(0).(func(context.Context, client.GetTokenByAuthCodeInput, chan<- string) *oidc.TokenSet); ok {
r0 = rf(ctx, in, localServerReadyChan)
} else {
if ret.Get(0) != nil {
@@ -214,8 +270,7 @@ func (_m *MockInterface) GetTokenByAuthCode(ctx context.Context, in GetTokenByAu
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, GetTokenByAuthCodeInput, chan<- string) error); ok {
if rf, ok := ret.Get(1).(func(context.Context, client.GetTokenByAuthCodeInput, chan<- string) error); ok {
r1 = rf(ctx, in, localServerReadyChan)
} else {
r1 = ret.Error(1)
@@ -231,15 +286,15 @@ type MockInterface_GetTokenByAuthCode_Call struct {
// GetTokenByAuthCode is a helper method to define mock.On call
// - ctx context.Context
// - in GetTokenByAuthCodeInput
// - in client.GetTokenByAuthCodeInput
// - localServerReadyChan chan<- string
func (_e *MockInterface_Expecter) GetTokenByAuthCode(ctx interface{}, in interface{}, localServerReadyChan interface{}) *MockInterface_GetTokenByAuthCode_Call {
return &MockInterface_GetTokenByAuthCode_Call{Call: _e.mock.On("GetTokenByAuthCode", ctx, in, localServerReadyChan)}
}
func (_c *MockInterface_GetTokenByAuthCode_Call) Run(run func(ctx context.Context, in GetTokenByAuthCodeInput, localServerReadyChan chan<- string)) *MockInterface_GetTokenByAuthCode_Call {
func (_c *MockInterface_GetTokenByAuthCode_Call) Run(run func(ctx context.Context, in client.GetTokenByAuthCodeInput, localServerReadyChan chan<- string)) *MockInterface_GetTokenByAuthCode_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(GetTokenByAuthCodeInput), args[2].(chan<- string))
run(args[0].(context.Context), args[1].(client.GetTokenByAuthCodeInput), args[2].(chan<- string))
})
return _c
}
@@ -249,11 +304,24 @@ func (_c *MockInterface_GetTokenByAuthCode_Call) Return(_a0 *oidc.TokenSet, _a1
return _c
}
func (_c *MockInterface_GetTokenByAuthCode_Call) RunAndReturn(run func(context.Context, client.GetTokenByAuthCodeInput, chan<- string) (*oidc.TokenSet, error)) *MockInterface_GetTokenByAuthCode_Call {
_c.Call.Return(run)
return _c
}
// GetTokenByROPC provides a mock function with given fields: ctx, username, password
func (_m *MockInterface) GetTokenByROPC(ctx context.Context, username string, password string) (*oidc.TokenSet, error) {
ret := _m.Called(ctx, username, password)
if len(ret) == 0 {
panic("no return value specified for GetTokenByROPC")
}
var r0 *oidc.TokenSet
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string, string) (*oidc.TokenSet, error)); ok {
return rf(ctx, username, password)
}
if rf, ok := ret.Get(0).(func(context.Context, string, string) *oidc.TokenSet); ok {
r0 = rf(ctx, username, password)
} else {
@@ -262,7 +330,6 @@ func (_m *MockInterface) GetTokenByROPC(ctx context.Context, username string, pa
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, string, string) error); ok {
r1 = rf(ctx, username, password)
} else {
@@ -297,11 +364,24 @@ func (_c *MockInterface_GetTokenByROPC_Call) Return(_a0 *oidc.TokenSet, _a1 erro
return _c
}
func (_c *MockInterface_GetTokenByROPC_Call) RunAndReturn(run func(context.Context, string, string) (*oidc.TokenSet, error)) *MockInterface_GetTokenByROPC_Call {
_c.Call.Return(run)
return _c
}
// Refresh provides a mock function with given fields: ctx, refreshToken
func (_m *MockInterface) Refresh(ctx context.Context, refreshToken string) (*oidc.TokenSet, error) {
ret := _m.Called(ctx, refreshToken)
if len(ret) == 0 {
panic("no return value specified for Refresh")
}
var r0 *oidc.TokenSet
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, string) (*oidc.TokenSet, error)); ok {
return rf(ctx, refreshToken)
}
if rf, ok := ret.Get(0).(func(context.Context, string) *oidc.TokenSet); ok {
r0 = rf(ctx, refreshToken)
} else {
@@ -310,7 +390,6 @@ func (_m *MockInterface) Refresh(ctx context.Context, refreshToken string) (*oid
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, refreshToken)
} else {
@@ -344,10 +423,19 @@ func (_c *MockInterface_Refresh_Call) Return(_a0 *oidc.TokenSet, _a1 error) *Moc
return _c
}
// SupportedPKCEMethods provides a mock function with given fields:
func (_c *MockInterface_Refresh_Call) RunAndReturn(run func(context.Context, string) (*oidc.TokenSet, error)) *MockInterface_Refresh_Call {
_c.Call.Return(run)
return _c
}
// SupportedPKCEMethods provides a mock function with no fields
func (_m *MockInterface) SupportedPKCEMethods() []string {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for SupportedPKCEMethods")
}
var r0 []string
if rf, ok := ret.Get(0).(func() []string); ok {
r0 = rf()
@@ -382,13 +470,17 @@ func (_c *MockInterface_SupportedPKCEMethods_Call) Return(_a0 []string) *MockInt
return _c
}
type mockConstructorTestingTNewMockInterface interface {
mock.TestingT
Cleanup(func())
func (_c *MockInterface_SupportedPKCEMethods_Call) RunAndReturn(run func() []string) *MockInterface_SupportedPKCEMethods_Call {
_c.Call.Return(run)
return _c
}
// NewMockInterface creates a new instance of MockInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockInterface(t mockConstructorTestingTNewMockInterface) *MockInterface {
// The first argument is typically a *testing.T value.
func NewMockInterface(t interface {
mock.TestingT
Cleanup(func())
}) *MockInterface {
mock := &MockInterface{}
mock.Mock.Test(t)

View File

@@ -0,0 +1,76 @@
// Code generated by mockery v2.50.4. DO NOT EDIT.
package logger_mock
import mock "github.com/stretchr/testify/mock"
// MocktestingLogger is an autogenerated mock type for the testingLogger type
type MocktestingLogger struct {
mock.Mock
}
type MocktestingLogger_Expecter struct {
mock *mock.Mock
}
func (_m *MocktestingLogger) EXPECT() *MocktestingLogger_Expecter {
return &MocktestingLogger_Expecter{mock: &_m.Mock}
}
// Logf provides a mock function with given fields: format, v
func (_m *MocktestingLogger) Logf(format string, v ...interface{}) {
var _ca []interface{}
_ca = append(_ca, format)
_ca = append(_ca, v...)
_m.Called(_ca...)
}
// MocktestingLogger_Logf_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Logf'
type MocktestingLogger_Logf_Call struct {
*mock.Call
}
// Logf is a helper method to define mock.On call
// - format string
// - v ...interface{}
func (_e *MocktestingLogger_Expecter) Logf(format interface{}, v ...interface{}) *MocktestingLogger_Logf_Call {
return &MocktestingLogger_Logf_Call{Call: _e.mock.On("Logf",
append([]interface{}{format}, v...)...)}
}
func (_c *MocktestingLogger_Logf_Call) Run(run func(format string, v ...interface{})) *MocktestingLogger_Logf_Call {
_c.Call.Run(func(args mock.Arguments) {
variadicArgs := make([]interface{}, len(args)-1)
for i, a := range args[1:] {
if a != nil {
variadicArgs[i] = a.(interface{})
}
}
run(args[0].(string), variadicArgs...)
})
return _c
}
func (_c *MocktestingLogger_Logf_Call) Return() *MocktestingLogger_Logf_Call {
_c.Call.Return()
return _c
}
func (_c *MocktestingLogger_Logf_Call) RunAndReturn(run func(string, ...interface{})) *MocktestingLogger_Logf_Call {
_c.Run(run)
return _c
}
// NewMocktestingLogger creates a new instance of MocktestingLogger. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewMocktestingLogger(t interface {
mock.TestingT
Cleanup(func())
}) *MocktestingLogger {
mock := &MocktestingLogger{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@@ -1,6 +1,6 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
// Code generated by mockery v2.50.4. DO NOT EDIT.
package loader
package loader_mock
import (
tls "crypto/tls"
@@ -27,7 +27,15 @@ func (_m *MockInterface) EXPECT() *MockInterface_Expecter {
func (_m *MockInterface) Load(config tlsclientconfig.Config) (*tls.Config, error) {
ret := _m.Called(config)
if len(ret) == 0 {
panic("no return value specified for Load")
}
var r0 *tls.Config
var r1 error
if rf, ok := ret.Get(0).(func(tlsclientconfig.Config) (*tls.Config, error)); ok {
return rf(config)
}
if rf, ok := ret.Get(0).(func(tlsclientconfig.Config) *tls.Config); ok {
r0 = rf(config)
} else {
@@ -36,7 +44,6 @@ func (_m *MockInterface) Load(config tlsclientconfig.Config) (*tls.Config, error
}
}
var r1 error
if rf, ok := ret.Get(1).(func(tlsclientconfig.Config) error); ok {
r1 = rf(config)
} else {
@@ -69,13 +76,17 @@ func (_c *MockInterface_Load_Call) Return(_a0 *tls.Config, _a1 error) *MockInter
return _c
}
type mockConstructorTestingTNewMockInterface interface {
mock.TestingT
Cleanup(func())
func (_c *MockInterface_Load_Call) RunAndReturn(run func(tlsclientconfig.Config) (*tls.Config, error)) *MockInterface_Load_Call {
_c.Call.Return(run)
return _c
}
// NewMockInterface creates a new instance of MockInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockInterface(t mockConstructorTestingTNewMockInterface) *MockInterface {
// The first argument is typically a *testing.T value.
func NewMockInterface(t interface {
mock.TestingT
Cleanup(func())
}) *MockInterface {
mock := &MockInterface{}
mock.Mock.Test(t)

View File

@@ -1,8 +1,10 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
// Code generated by mockery v2.50.4. DO NOT EDIT.
package repository
package repository_mock
import (
io "io"
oidc "github.com/int128/kubelogin/pkg/oidc"
mock "github.com/stretchr/testify/mock"
@@ -26,7 +28,15 @@ func (_m *MockInterface) EXPECT() *MockInterface_Expecter {
func (_m *MockInterface) FindByKey(dir string, key tokencache.Key) (*oidc.TokenSet, error) {
ret := _m.Called(dir, key)
if len(ret) == 0 {
panic("no return value specified for FindByKey")
}
var r0 *oidc.TokenSet
var r1 error
if rf, ok := ret.Get(0).(func(string, tokencache.Key) (*oidc.TokenSet, error)); ok {
return rf(dir, key)
}
if rf, ok := ret.Get(0).(func(string, tokencache.Key) *oidc.TokenSet); ok {
r0 = rf(dir, key)
} else {
@@ -35,7 +45,6 @@ func (_m *MockInterface) FindByKey(dir string, key tokencache.Key) (*oidc.TokenS
}
}
var r1 error
if rf, ok := ret.Get(1).(func(string, tokencache.Key) error); ok {
r1 = rf(dir, key)
} else {
@@ -69,10 +78,78 @@ func (_c *MockInterface_FindByKey_Call) Return(_a0 *oidc.TokenSet, _a1 error) *M
return _c
}
func (_c *MockInterface_FindByKey_Call) RunAndReturn(run func(string, tokencache.Key) (*oidc.TokenSet, error)) *MockInterface_FindByKey_Call {
_c.Call.Return(run)
return _c
}
// Lock provides a mock function with given fields: dir, key
func (_m *MockInterface) Lock(dir string, key tokencache.Key) (io.Closer, error) {
ret := _m.Called(dir, key)
if len(ret) == 0 {
panic("no return value specified for Lock")
}
var r0 io.Closer
var r1 error
if rf, ok := ret.Get(0).(func(string, tokencache.Key) (io.Closer, error)); ok {
return rf(dir, key)
}
if rf, ok := ret.Get(0).(func(string, tokencache.Key) io.Closer); ok {
r0 = rf(dir, key)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(io.Closer)
}
}
if rf, ok := ret.Get(1).(func(string, tokencache.Key) error); ok {
r1 = rf(dir, key)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockInterface_Lock_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Lock'
type MockInterface_Lock_Call struct {
*mock.Call
}
// Lock is a helper method to define mock.On call
// - dir string
// - key tokencache.Key
func (_e *MockInterface_Expecter) Lock(dir interface{}, key interface{}) *MockInterface_Lock_Call {
return &MockInterface_Lock_Call{Call: _e.mock.On("Lock", dir, key)}
}
func (_c *MockInterface_Lock_Call) Run(run func(dir string, key tokencache.Key)) *MockInterface_Lock_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(string), args[1].(tokencache.Key))
})
return _c
}
func (_c *MockInterface_Lock_Call) Return(_a0 io.Closer, _a1 error) *MockInterface_Lock_Call {
_c.Call.Return(_a0, _a1)
return _c
}
func (_c *MockInterface_Lock_Call) RunAndReturn(run func(string, tokencache.Key) (io.Closer, error)) *MockInterface_Lock_Call {
_c.Call.Return(run)
return _c
}
// Save provides a mock function with given fields: dir, key, tokenSet
func (_m *MockInterface) Save(dir string, key tokencache.Key, tokenSet oidc.TokenSet) error {
ret := _m.Called(dir, key, tokenSet)
if len(ret) == 0 {
panic("no return value specified for Save")
}
var r0 error
if rf, ok := ret.Get(0).(func(string, tokencache.Key, oidc.TokenSet) error); ok {
r0 = rf(dir, key, tokenSet)
@@ -108,13 +185,17 @@ func (_c *MockInterface_Save_Call) Return(_a0 error) *MockInterface_Save_Call {
return _c
}
type mockConstructorTestingTNewMockInterface interface {
mock.TestingT
Cleanup(func())
func (_c *MockInterface_Save_Call) RunAndReturn(run func(string, tokencache.Key, oidc.TokenSet) error) *MockInterface_Save_Call {
_c.Call.Return(run)
return _c
}
// NewMockInterface creates a new instance of MockInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockInterface(t mockConstructorTestingTNewMockInterface) *MockInterface {
// The first argument is typically a *testing.T value.
func NewMockInterface(t interface {
mock.TestingT
Cleanup(func())
}) *MockInterface {
mock := &MockInterface{}
mock.Mock.Test(t)

View File

@@ -1,10 +1,12 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
// Code generated by mockery v2.50.4. DO NOT EDIT.
package authentication
package authentication_mock
import (
context "context"
authentication "github.com/int128/kubelogin/pkg/usecases/authentication"
mock "github.com/stretchr/testify/mock"
)
@@ -22,20 +24,27 @@ func (_m *MockInterface) EXPECT() *MockInterface_Expecter {
}
// Do provides a mock function with given fields: ctx, in
func (_m *MockInterface) Do(ctx context.Context, in Input) (*Output, error) {
func (_m *MockInterface) Do(ctx context.Context, in authentication.Input) (*authentication.Output, error) {
ret := _m.Called(ctx, in)
var r0 *Output
if rf, ok := ret.Get(0).(func(context.Context, Input) *Output); ok {
if len(ret) == 0 {
panic("no return value specified for Do")
}
var r0 *authentication.Output
var r1 error
if rf, ok := ret.Get(0).(func(context.Context, authentication.Input) (*authentication.Output, error)); ok {
return rf(ctx, in)
}
if rf, ok := ret.Get(0).(func(context.Context, authentication.Input) *authentication.Output); ok {
r0 = rf(ctx, in)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*Output)
r0 = ret.Get(0).(*authentication.Output)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, Input) error); ok {
if rf, ok := ret.Get(1).(func(context.Context, authentication.Input) error); ok {
r1 = rf(ctx, in)
} else {
r1 = ret.Error(1)
@@ -51,30 +60,34 @@ type MockInterface_Do_Call struct {
// Do is a helper method to define mock.On call
// - ctx context.Context
// - in Input
// - in authentication.Input
func (_e *MockInterface_Expecter) Do(ctx interface{}, in interface{}) *MockInterface_Do_Call {
return &MockInterface_Do_Call{Call: _e.mock.On("Do", ctx, in)}
}
func (_c *MockInterface_Do_Call) Run(run func(ctx context.Context, in Input)) *MockInterface_Do_Call {
func (_c *MockInterface_Do_Call) Run(run func(ctx context.Context, in authentication.Input)) *MockInterface_Do_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(Input))
run(args[0].(context.Context), args[1].(authentication.Input))
})
return _c
}
func (_c *MockInterface_Do_Call) Return(_a0 *Output, _a1 error) *MockInterface_Do_Call {
func (_c *MockInterface_Do_Call) Return(_a0 *authentication.Output, _a1 error) *MockInterface_Do_Call {
_c.Call.Return(_a0, _a1)
return _c
}
type mockConstructorTestingTNewMockInterface interface {
mock.TestingT
Cleanup(func())
func (_c *MockInterface_Do_Call) RunAndReturn(run func(context.Context, authentication.Input) (*authentication.Output, error)) *MockInterface_Do_Call {
_c.Call.Return(run)
return _c
}
// NewMockInterface creates a new instance of MockInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockInterface(t mockConstructorTestingTNewMockInterface) *MockInterface {
// The first argument is typically a *testing.T value.
func NewMockInterface(t interface {
mock.TestingT
Cleanup(func())
}) *MockInterface {
mock := &MockInterface{}
mock.Mock.Test(t)

View File

@@ -1,10 +1,11 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
// Code generated by mockery v2.50.4. DO NOT EDIT.
package standalone
package credentialplugin_mock
import (
context "context"
credentialplugin "github.com/int128/kubelogin/pkg/usecases/credentialplugin"
mock "github.com/stretchr/testify/mock"
)
@@ -22,11 +23,15 @@ func (_m *MockInterface) EXPECT() *MockInterface_Expecter {
}
// Do provides a mock function with given fields: ctx, in
func (_m *MockInterface) Do(ctx context.Context, in Input) error {
func (_m *MockInterface) Do(ctx context.Context, in credentialplugin.Input) error {
ret := _m.Called(ctx, in)
if len(ret) == 0 {
panic("no return value specified for Do")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, Input) error); ok {
if rf, ok := ret.Get(0).(func(context.Context, credentialplugin.Input) error); ok {
r0 = rf(ctx, in)
} else {
r0 = ret.Error(0)
@@ -42,14 +47,14 @@ type MockInterface_Do_Call struct {
// Do is a helper method to define mock.On call
// - ctx context.Context
// - in Input
// - in credentialplugin.Input
func (_e *MockInterface_Expecter) Do(ctx interface{}, in interface{}) *MockInterface_Do_Call {
return &MockInterface_Do_Call{Call: _e.mock.On("Do", ctx, in)}
}
func (_c *MockInterface_Do_Call) Run(run func(ctx context.Context, in Input)) *MockInterface_Do_Call {
func (_c *MockInterface_Do_Call) Run(run func(ctx context.Context, in credentialplugin.Input)) *MockInterface_Do_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(Input))
run(args[0].(context.Context), args[1].(credentialplugin.Input))
})
return _c
}
@@ -59,13 +64,17 @@ func (_c *MockInterface_Do_Call) Return(_a0 error) *MockInterface_Do_Call {
return _c
}
type mockConstructorTestingTNewMockInterface interface {
mock.TestingT
Cleanup(func())
func (_c *MockInterface_Do_Call) RunAndReturn(run func(context.Context, credentialplugin.Input) error) *MockInterface_Do_Call {
_c.Call.Return(run)
return _c
}
// NewMockInterface creates a new instance of MockInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockInterface(t mockConstructorTestingTNewMockInterface) *MockInterface {
// The first argument is typically a *testing.T value.
func NewMockInterface(t interface {
mock.TestingT
Cleanup(func())
}) *MockInterface {
mock := &MockInterface{}
mock.Mock.Test(t)

View File

@@ -1,10 +1,11 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
// Code generated by mockery v2.50.4. DO NOT EDIT.
package setup
package setup_mock
import (
context "context"
setup "github.com/int128/kubelogin/pkg/usecases/setup"
mock "github.com/stretchr/testify/mock"
)
@@ -21,7 +22,7 @@ func (_m *MockInterface) EXPECT() *MockInterface_Expecter {
return &MockInterface_Expecter{mock: &_m.Mock}
}
// DoStage1 provides a mock function with given fields:
// DoStage1 provides a mock function with no fields
func (_m *MockInterface) DoStage1() {
_m.Called()
}
@@ -48,12 +49,21 @@ func (_c *MockInterface_DoStage1_Call) Return() *MockInterface_DoStage1_Call {
return _c
}
func (_c *MockInterface_DoStage1_Call) RunAndReturn(run func()) *MockInterface_DoStage1_Call {
_c.Run(run)
return _c
}
// DoStage2 provides a mock function with given fields: ctx, in
func (_m *MockInterface) DoStage2(ctx context.Context, in Stage2Input) error {
func (_m *MockInterface) DoStage2(ctx context.Context, in setup.Stage2Input) error {
ret := _m.Called(ctx, in)
if len(ret) == 0 {
panic("no return value specified for DoStage2")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, Stage2Input) error); ok {
if rf, ok := ret.Get(0).(func(context.Context, setup.Stage2Input) error); ok {
r0 = rf(ctx, in)
} else {
r0 = ret.Error(0)
@@ -69,14 +79,14 @@ type MockInterface_DoStage2_Call struct {
// DoStage2 is a helper method to define mock.On call
// - ctx context.Context
// - in Stage2Input
// - in setup.Stage2Input
func (_e *MockInterface_Expecter) DoStage2(ctx interface{}, in interface{}) *MockInterface_DoStage2_Call {
return &MockInterface_DoStage2_Call{Call: _e.mock.On("DoStage2", ctx, in)}
}
func (_c *MockInterface_DoStage2_Call) Run(run func(ctx context.Context, in Stage2Input)) *MockInterface_DoStage2_Call {
func (_c *MockInterface_DoStage2_Call) Run(run func(ctx context.Context, in setup.Stage2Input)) *MockInterface_DoStage2_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(Stage2Input))
run(args[0].(context.Context), args[1].(setup.Stage2Input))
})
return _c
}
@@ -86,13 +96,17 @@ func (_c *MockInterface_DoStage2_Call) Return(_a0 error) *MockInterface_DoStage2
return _c
}
type mockConstructorTestingTNewMockInterface interface {
mock.TestingT
Cleanup(func())
func (_c *MockInterface_DoStage2_Call) RunAndReturn(run func(context.Context, setup.Stage2Input) error) *MockInterface_DoStage2_Call {
_c.Call.Return(run)
return _c
}
// NewMockInterface creates a new instance of MockInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockInterface(t mockConstructorTestingTNewMockInterface) *MockInterface {
// The first argument is typically a *testing.T value.
func NewMockInterface(t interface {
mock.TestingT
Cleanup(func())
}) *MockInterface {
mock := &MockInterface{}
mock.Mock.Test(t)

View File

@@ -1,10 +1,11 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
// Code generated by mockery v2.50.4. DO NOT EDIT.
package credentialplugin
package standalone_mock
import (
context "context"
standalone "github.com/int128/kubelogin/pkg/usecases/standalone"
mock "github.com/stretchr/testify/mock"
)
@@ -22,11 +23,15 @@ func (_m *MockInterface) EXPECT() *MockInterface_Expecter {
}
// Do provides a mock function with given fields: ctx, in
func (_m *MockInterface) Do(ctx context.Context, in Input) error {
func (_m *MockInterface) Do(ctx context.Context, in standalone.Input) error {
ret := _m.Called(ctx, in)
if len(ret) == 0 {
panic("no return value specified for Do")
}
var r0 error
if rf, ok := ret.Get(0).(func(context.Context, Input) error); ok {
if rf, ok := ret.Get(0).(func(context.Context, standalone.Input) error); ok {
r0 = rf(ctx, in)
} else {
r0 = ret.Error(0)
@@ -42,14 +47,14 @@ type MockInterface_Do_Call struct {
// Do is a helper method to define mock.On call
// - ctx context.Context
// - in Input
// - in standalone.Input
func (_e *MockInterface_Expecter) Do(ctx interface{}, in interface{}) *MockInterface_Do_Call {
return &MockInterface_Do_Call{Call: _e.mock.On("Do", ctx, in)}
}
func (_c *MockInterface_Do_Call) Run(run func(ctx context.Context, in Input)) *MockInterface_Do_Call {
func (_c *MockInterface_Do_Call) Run(run func(ctx context.Context, in standalone.Input)) *MockInterface_Do_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(Input))
run(args[0].(context.Context), args[1].(standalone.Input))
})
return _c
}
@@ -59,13 +64,17 @@ func (_c *MockInterface_Do_Call) Return(_a0 error) *MockInterface_Do_Call {
return _c
}
type mockConstructorTestingTNewMockInterface interface {
mock.TestingT
Cleanup(func())
func (_c *MockInterface_Do_Call) RunAndReturn(run func(context.Context, standalone.Input) error) *MockInterface_Do_Call {
_c.Call.Return(run)
return _c
}
// NewMockInterface creates a new instance of MockInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockInterface(t mockConstructorTestingTNewMockInterface) *MockInterface {
// The first argument is typically a *testing.T value.
func NewMockInterface(t interface {
mock.TestingT
Cleanup(func())
}) *MockInterface {
mock := &MockInterface{}
mock.Mock.Test(t)

View File

@@ -0,0 +1,77 @@
// Code generated by mockery v2.50.4. DO NOT EDIT.
package io_mock
import mock "github.com/stretchr/testify/mock"
// MockCloser is an autogenerated mock type for the Closer type
type MockCloser struct {
mock.Mock
}
type MockCloser_Expecter struct {
mock *mock.Mock
}
func (_m *MockCloser) EXPECT() *MockCloser_Expecter {
return &MockCloser_Expecter{mock: &_m.Mock}
}
// Close provides a mock function with no fields
func (_m *MockCloser) Close() error {
ret := _m.Called()
if len(ret) == 0 {
panic("no return value specified for Close")
}
var r0 error
if rf, ok := ret.Get(0).(func() error); ok {
r0 = rf()
} else {
r0 = ret.Error(0)
}
return r0
}
// MockCloser_Close_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Close'
type MockCloser_Close_Call struct {
*mock.Call
}
// Close is a helper method to define mock.On call
func (_e *MockCloser_Expecter) Close() *MockCloser_Close_Call {
return &MockCloser_Close_Call{Call: _e.mock.On("Close")}
}
func (_c *MockCloser_Close_Call) Run(run func()) *MockCloser_Close_Call {
_c.Call.Run(func(args mock.Arguments) {
run()
})
return _c
}
func (_c *MockCloser_Close_Call) Return(_a0 error) *MockCloser_Close_Call {
_c.Call.Return(_a0)
return _c
}
func (_c *MockCloser_Close_Call) RunAndReturn(run func() error) *MockCloser_Close_Call {
_c.Call.Return(run)
return _c
}
// NewMockCloser creates a new instance of MockCloser. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
// The first argument is typically a *testing.T value.
func NewMockCloser(t interface {
mock.TestingT
Cleanup(func())
}) *MockCloser {
mock := &MockCloser{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@@ -17,7 +17,6 @@ const oobRedirectURI = "urn:ietf:wg:oauth:2.0:oob"
type authenticationOptions struct {
GrantType string
ListenAddress []string
ListenPort []int // deprecated
AuthenticationTimeoutSec int
SkipOpenBrowser bool
BrowserCommand string
@@ -31,21 +30,6 @@ type authenticationOptions struct {
Password string
}
// determineListenAddress returns the addresses from the flags.
// Note that --listen-address is always given due to the default value.
// If --listen-port is not set, it returns --listen-address.
// If --listen-port is set, it returns the strings of --listen-port.
func (o *authenticationOptions) determineListenAddress() []string {
if len(o.ListenPort) == 0 {
return o.ListenAddress
}
var a []string
for _, p := range o.ListenPort {
a = append(a, fmt.Sprintf("127.0.0.1:%d", p))
}
return a
}
var allGrantType = strings.Join([]string{
"auto",
"authcode",
@@ -57,11 +41,6 @@ var allGrantType = strings.Join([]string{
func (o *authenticationOptions) addFlags(f *pflag.FlagSet) {
f.StringVar(&o.GrantType, "grant-type", "auto", fmt.Sprintf("Authorization grant type to use. One of (%s)", allGrantType))
f.StringSliceVar(&o.ListenAddress, "listen-address", defaultListenAddress, "[authcode] Address to bind to the local server. If multiple addresses are set, it will try binding in order")
//TODO: remove the deprecated flag
f.IntSliceVar(&o.ListenPort, "listen-port", nil, "[authcode] deprecated: port to bind to the local server")
if err := f.MarkDeprecated("listen-port", "use --listen-address instead"); err != nil {
panic(err)
}
f.BoolVar(&o.SkipOpenBrowser, "skip-open-browser", false, "[authcode] Do not open the browser automatically")
f.StringVar(&o.BrowserCommand, "browser-command", "", "[authcode] Command to open the browser")
f.IntVar(&o.AuthenticationTimeoutSec, "authentication-timeout-sec", defaultAuthenticationTimeoutSec, "[authcode] Timeout of authentication in seconds")
@@ -84,7 +63,7 @@ func (o *authenticationOptions) grantOptionSet() (s authentication.GrantOptionSe
switch {
case o.GrantType == "authcode" || (o.GrantType == "auto" && o.Username == ""):
s.AuthCodeBrowserOption = &authcode.BrowserOption{
BindAddress: o.determineListenAddress(),
BindAddress: o.ListenAddress,
SkipOpenBrowser: o.SkipOpenBrowser,
BrowserCommand: o.BrowserCommand,
AuthenticationTimeout: time.Duration(o.AuthenticationTimeoutSec) * time.Second,

View File

@@ -56,34 +56,6 @@ func Test_authenticationOptions_grantOptionSet(t *testing.T) {
},
},
},
"when --listen-port is set, it should convert the port to address": {
args: []string{
"--listen-port", "10080",
"--listen-port", "20080",
},
want: authentication.GrantOptionSet{
AuthCodeBrowserOption: &authcode.BrowserOption{
BindAddress: []string{"127.0.0.1:10080", "127.0.0.1:20080"},
AuthenticationTimeout: defaultAuthenticationTimeoutSec * time.Second,
RedirectURLHostname: "localhost",
},
},
},
"when --listen-port is set, it should ignore --listen-address flags": {
args: []string{
"--listen-port", "10080",
"--listen-port", "20080",
"--listen-address", "127.0.0.1:30080",
"--listen-address", "127.0.0.1:40080",
},
want: authentication.GrantOptionSet{
AuthCodeBrowserOption: &authcode.BrowserOption{
BindAddress: []string{"127.0.0.1:10080", "127.0.0.1:20080"},
AuthenticationTimeout: defaultAuthenticationTimeoutSec * time.Second,
RedirectURLHostname: "localhost",
},
},
},
"GrantType=authcode-keyboard": {
args: []string{
"--grant-type", "authcode-keyboard",

View File

@@ -7,6 +7,8 @@ import (
"testing"
"time"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/usecases/credentialplugin_mock"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/usecases/standalone_mock"
"github.com/int128/kubelogin/pkg/oidc"
"github.com/int128/kubelogin/pkg/testing/logger"
"github.com/int128/kubelogin/pkg/tlsclientconfig"
@@ -61,7 +63,7 @@ func TestCmd_Run(t *testing.T) {
for name, c := range tests {
t.Run(name, func(t *testing.T) {
ctx := context.TODO()
mockStandalone := standalone.NewMockInterface(t)
mockStandalone := standalone_mock.NewMockInterface(t)
mockStandalone.EXPECT().
Do(ctx, c.in).
Return(nil)
@@ -82,7 +84,7 @@ func TestCmd_Run(t *testing.T) {
t.Run("TooManyArgs", func(t *testing.T) {
cmd := Cmd{
Root: &Root{
Standalone: standalone.NewMockInterface(t),
Standalone: standalone_mock.NewMockInterface(t),
Logger: logger.New(t),
},
Logger: logger.New(t),
@@ -152,6 +154,29 @@ func TestCmd_Run(t *testing.T) {
},
},
},
"AccessToken": {
args: []string{executable,
"get-token",
"--oidc-issuer-url", "https://issuer.example.com",
"--oidc-client-id", "YOUR_CLIENT_ID",
"--oidc-use-access-token=true",
},
in: credentialplugin.Input{
TokenCacheDir: filepath.Join(userHomeDir, ".kube/cache/oidc-login"),
Provider: oidc.Provider{
IssuerURL: "https://issuer.example.com",
ClientID: "YOUR_CLIENT_ID",
UseAccessToken: true,
},
GrantOptionSet: authentication.GrantOptionSet{
AuthCodeBrowserOption: &authcode.BrowserOption{
BindAddress: defaultListenAddress,
AuthenticationTimeout: defaultAuthenticationTimeoutSec * time.Second,
RedirectURLHostname: "localhost",
},
},
},
},
"HomedirExpansion": {
args: []string{executable,
"get-token",
@@ -186,7 +211,7 @@ func TestCmd_Run(t *testing.T) {
for name, c := range tests {
t.Run(name, func(t *testing.T) {
ctx := context.TODO()
getToken := credentialplugin.NewMockInterface(t)
getToken := credentialplugin_mock.NewMockInterface(t)
getToken.EXPECT().
Do(ctx, c.in).
Return(nil)
@@ -214,7 +239,7 @@ func TestCmd_Run(t *testing.T) {
Logger: logger.New(t),
},
GetToken: &GetToken{
GetToken: credentialplugin.NewMockInterface(t),
GetToken: credentialplugin_mock.NewMockInterface(t),
Logger: logger.New(t),
},
Logger: logger.New(t),
@@ -232,7 +257,7 @@ func TestCmd_Run(t *testing.T) {
Logger: logger.New(t),
},
GetToken: &GetToken{
GetToken: credentialplugin.NewMockInterface(t),
GetToken: credentialplugin_mock.NewMockInterface(t),
Logger: logger.New(t),
},
Logger: logger.New(t),

View File

@@ -18,6 +18,7 @@ type getTokenOptions struct {
ClientSecret string
ExtraScopes []string
UsePKCE bool
UseAccessToken bool
TokenCacheDir string
tlsOptions tlsOptions
authenticationOptions authenticationOptions
@@ -30,6 +31,7 @@ func (o *getTokenOptions) addFlags(f *pflag.FlagSet) {
f.StringVar(&o.ClientSecret, "oidc-client-secret", "", "Client secret of the provider")
f.StringSliceVar(&o.ExtraScopes, "oidc-extra-scope", nil, "Scopes to request to the provider")
f.BoolVar(&o.UsePKCE, "oidc-use-pkce", false, "Force PKCE usage")
f.BoolVar(&o.UseAccessToken, "oidc-use-access-token", false, "Instead of using the id_token, use the access_token to authenticate to Kubernetes")
f.StringVar(&o.TokenCacheDir, "token-cache-dir", defaultTokenCacheDir, "Path to a directory for token cache")
f.BoolVar(&o.ForceRefresh, "force-refresh", false, "If set, refresh the ID token regardless of its expiration time")
o.tlsOptions.addFlags(f)
@@ -75,11 +77,12 @@ func (cmd *GetToken) New() *cobra.Command {
}
in := credentialplugin.Input{
Provider: oidc.Provider{
IssuerURL: o.IssuerURL,
ClientID: o.ClientID,
ClientSecret: o.ClientSecret,
UsePKCE: o.UsePKCE,
ExtraScopes: o.ExtraScopes,
IssuerURL: o.IssuerURL,
ClientID: o.ClientID,
ClientSecret: o.ClientSecret,
UsePKCE: o.UsePKCE,
UseAccessToken: o.UseAccessToken,
ExtraScopes: o.ExtraScopes,
},
TokenCacheDir: o.TokenCacheDir,
GrantOptionSet: grantOptionSet,

View File

@@ -15,6 +15,7 @@ type setupOptions struct {
ClientSecret string
ExtraScopes []string
UsePKCE bool
UseAccessToken bool
tlsOptions tlsOptions
authenticationOptions authenticationOptions
}
@@ -25,6 +26,7 @@ func (o *setupOptions) addFlags(f *pflag.FlagSet) {
f.StringVar(&o.ClientSecret, "oidc-client-secret", "", "Client secret of the provider")
f.StringSliceVar(&o.ExtraScopes, "oidc-extra-scope", nil, "Scopes to request to the provider")
f.BoolVar(&o.UsePKCE, "oidc-use-pkce", false, "Force PKCE usage")
f.BoolVar(&o.UseAccessToken, "oidc-use-access-token", false, "Instead of using the id_token, use the access_token to authenticate to Kubernetes")
o.tlsOptions.addFlags(f)
o.authenticationOptions.addFlags(f)
}
@@ -50,6 +52,7 @@ func (cmd *Setup) New() *cobra.Command {
ClientSecret: o.ClientSecret,
ExtraScopes: o.ExtraScopes,
UsePKCE: o.UsePKCE,
UseAccessToken: o.UseAccessToken,
GrantOptionSet: grantOptionSet,
TLSClientConfig: o.tlsOptions.tlsClientConfig(),
}

View File

@@ -0,0 +1,39 @@
// Package reader provides a loader for the credential plugin.
package reader
import (
"encoding/json"
"fmt"
"os"
"github.com/google/wire"
"github.com/int128/kubelogin/pkg/credentialplugin"
"k8s.io/client-go/pkg/apis/clientauthentication"
)
var Set = wire.NewSet(
wire.Struct(new(Reader), "*"),
wire.Bind(new(Interface), new(*Reader)),
)
type Interface interface {
Read() (credentialplugin.Input, error)
}
type Reader struct{}
// Read parses the environment variable KUBERNETES_EXEC_INFO.
// If the environment variable is not given by kubectl, Read returns a zero value.
func (r Reader) Read() (credentialplugin.Input, error) {
execInfo := os.Getenv("KUBERNETES_EXEC_INFO")
if execInfo == "" {
return credentialplugin.Input{}, nil
}
var execCredential clientauthentication.ExecCredential
if err := json.Unmarshal([]byte(execInfo), &execCredential); err != nil {
return credentialplugin.Input{}, fmt.Errorf("invalid KUBERNETES_EXEC_INFO: %w", err)
}
return credentialplugin.Input{
ClientAuthenticationAPIVersion: execCredential.APIVersion,
}, nil
}

View File

@@ -0,0 +1,44 @@
package reader
import (
"testing"
"github.com/google/go-cmp/cmp"
"github.com/int128/kubelogin/pkg/credentialplugin"
)
func TestReader_Read(t *testing.T) {
var reader Reader
t.Run("KUBERNETES_EXEC_INFO is empty", func(t *testing.T) {
input, err := reader.Read()
if err != nil {
t.Errorf("Read returned error: %v", err)
}
want := credentialplugin.Input{}
if diff := cmp.Diff(want, input); diff != "" {
t.Errorf("input mismatch (-want +got):\n%s", diff)
}
})
t.Run("KUBERNETES_EXEC_INFO is invalid JSON", func(t *testing.T) {
t.Setenv("KUBERNETES_EXEC_INFO", "invalid")
_, err := reader.Read()
if err == nil {
t.Errorf("Read wants error but no error")
}
})
t.Run("KUBERNETES_EXEC_INFO is v1", func(t *testing.T) {
t.Setenv(
"KUBERNETES_EXEC_INFO",
`{"kind":"ExecCredential","apiVersion":"client.authentication.k8s.io/v1","spec":{"interactive":true}}`,
)
input, err := reader.Read()
if err != nil {
t.Errorf("Read returned error: %v", err)
}
want := credentialplugin.Input{ClientAuthenticationAPIVersion: "client.authentication.k8s.io/v1"}
if diff := cmp.Diff(want, input); diff != "" {
t.Errorf("input mismatch (-want +got):\n%s", diff)
}
})
}

View File

@@ -3,8 +3,15 @@ package credentialplugin
import "time"
// Input represents an input object of the credential plugin.
// This may be a zero value if the input is not available.
type Input struct {
ClientAuthenticationAPIVersion string
}
// Output represents an output object of the credential plugin.
type Output struct {
Token string
Expiry time.Time
Token string
Expiry time.Time
ClientAuthenticationAPIVersion string
}

View File

@@ -1,4 +1,4 @@
// Package writer provides a writer for a credential plugin.
// Package writer provides a writer for the credential plugin.
package writer
import (
@@ -9,6 +9,7 @@ import (
"github.com/int128/kubelogin/pkg/credentialplugin"
"github.com/int128/kubelogin/pkg/infrastructure/stdio"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clientauthenticationv1 "k8s.io/client-go/pkg/apis/clientauthentication/v1"
clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
)
@@ -27,19 +28,44 @@ type Writer struct {
// Write writes the ExecCredential to standard output for kubectl.
func (w *Writer) Write(out credentialplugin.Output) error {
ec := &clientauthenticationv1beta1.ExecCredential{
TypeMeta: metav1.TypeMeta{
APIVersion: "client.authentication.k8s.io/v1beta1",
Kind: "ExecCredential",
},
Status: &clientauthenticationv1beta1.ExecCredentialStatus{
Token: out.Token,
ExpirationTimestamp: &metav1.Time{Time: out.Expiry},
},
execCredential, err := generateExecCredential(out)
if err != nil {
return fmt.Errorf("generate ExecCredential: %w", err)
}
e := json.NewEncoder(w.Stdout)
if err := e.Encode(ec); err != nil {
return fmt.Errorf("could not write the ExecCredential: %w", err)
if err := json.NewEncoder(w.Stdout).Encode(execCredential); err != nil {
return fmt.Errorf("write ExecCredential: %w", err)
}
return nil
}
func generateExecCredential(out credentialplugin.Output) (any, error) {
switch out.ClientAuthenticationAPIVersion {
// If the API version is not available, fall back to v1beta1.
case clientauthenticationv1beta1.SchemeGroupVersion.String(), "":
return &clientauthenticationv1beta1.ExecCredential{
TypeMeta: metav1.TypeMeta{
APIVersion: clientauthenticationv1beta1.SchemeGroupVersion.String(),
Kind: "ExecCredential",
},
Status: &clientauthenticationv1beta1.ExecCredentialStatus{
Token: out.Token,
ExpirationTimestamp: &metav1.Time{Time: out.Expiry},
},
}, nil
case clientauthenticationv1.SchemeGroupVersion.String():
return &clientauthenticationv1.ExecCredential{
TypeMeta: metav1.TypeMeta{
APIVersion: clientauthenticationv1.SchemeGroupVersion.String(),
Kind: "ExecCredential",
},
Status: &clientauthenticationv1.ExecCredentialStatus{
Token: out.Token,
ExpirationTimestamp: &metav1.Time{Time: out.Expiry},
},
}, nil
default:
return nil, fmt.Errorf("unknown apiVersion: %s", out.ClientAuthenticationAPIVersion)
}
}

View File

@@ -7,11 +7,11 @@ package di
import (
"github.com/google/wire"
"github.com/int128/kubelogin/pkg/cmd"
"github.com/int128/kubelogin/pkg/credentialplugin/writer"
credentialpluginreader "github.com/int128/kubelogin/pkg/credentialplugin/reader"
credentialpluginwriter "github.com/int128/kubelogin/pkg/credentialplugin/writer"
"github.com/int128/kubelogin/pkg/infrastructure/browser"
"github.com/int128/kubelogin/pkg/infrastructure/clock"
"github.com/int128/kubelogin/pkg/infrastructure/logger"
"github.com/int128/kubelogin/pkg/infrastructure/mutex"
"github.com/int128/kubelogin/pkg/infrastructure/reader"
"github.com/int128/kubelogin/pkg/infrastructure/stdio"
kubeconfigLoader "github.com/int128/kubelogin/pkg/kubeconfig/loader"
@@ -56,8 +56,8 @@ func NewCmdForHeadless(clock.Interface, stdio.Stdin, stdio.Stdout, logger.Interf
repository.Set,
client.Set,
loader.Set,
writer.Set,
mutex.Set,
credentialpluginreader.Set,
credentialpluginwriter.Set,
)
return nil
}

View File

@@ -1,6 +1,6 @@
// Code generated by Wire. DO NOT EDIT.
//go:generate go run github.com/google/wire/cmd/wire
//go:generate go run -mod=mod github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject
@@ -8,11 +8,11 @@ package di
import (
"github.com/int128/kubelogin/pkg/cmd"
reader2 "github.com/int128/kubelogin/pkg/credentialplugin/reader"
writer2 "github.com/int128/kubelogin/pkg/credentialplugin/writer"
"github.com/int128/kubelogin/pkg/infrastructure/browser"
"github.com/int128/kubelogin/pkg/infrastructure/clock"
"github.com/int128/kubelogin/pkg/infrastructure/logger"
"github.com/int128/kubelogin/pkg/infrastructure/mutex"
"github.com/int128/kubelogin/pkg/infrastructure/reader"
"github.com/int128/kubelogin/pkg/infrastructure/stdio"
loader2 "github.com/int128/kubelogin/pkg/kubeconfig/loader"
@@ -78,7 +78,6 @@ func NewCmdForHeadless(clockInterface clock.Interface, stdin stdio.Stdin, stdout
authenticationAuthentication := &authentication.Authentication{
ClientFactory: factory,
Logger: loggerInterface,
Clock: clockInterface,
AuthCodeBrowser: authcodeBrowser,
AuthCodeKeyboard: keyboard,
ROPC: ropcROPC,
@@ -91,24 +90,24 @@ func NewCmdForHeadless(clockInterface clock.Interface, stdin stdio.Stdin, stdout
KubeconfigLoader: loader3,
KubeconfigWriter: writerWriter,
Logger: loggerInterface,
Clock: clockInterface,
}
root := &cmd.Root{
Standalone: standaloneStandalone,
Logger: loggerInterface,
}
repositoryRepository := &repository.Repository{}
reader3 := &reader2.Reader{}
writer3 := &writer2.Writer{
Stdout: stdout,
}
mutexMutex := &mutex.Mutex{
Logger: loggerInterface,
}
getToken := &credentialplugin.GetToken{
Authentication: authenticationAuthentication,
TokenCacheRepository: repositoryRepository,
Writer: writer3,
Mutex: mutexMutex,
Logger: loggerInterface,
Authentication: authenticationAuthentication,
TokenCacheRepository: repositoryRepository,
CredentialPluginReader: reader3,
CredentialPluginWriter: writer3,
Logger: loggerInterface,
Clock: clockInterface,
}
cmdGetToken := &cmd.GetToken{
GetToken: getToken,

View File

@@ -1,72 +0,0 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
package logger
import mock "github.com/stretchr/testify/mock"
// mockGoLogger is an autogenerated mock type for the goLogger type
type mockGoLogger struct {
mock.Mock
}
type mockGoLogger_Expecter struct {
mock *mock.Mock
}
func (_m *mockGoLogger) EXPECT() *mockGoLogger_Expecter {
return &mockGoLogger_Expecter{mock: &_m.Mock}
}
// Printf provides a mock function with given fields: format, v
func (_m *mockGoLogger) Printf(format string, v ...interface{}) {
var _ca []interface{}
_ca = append(_ca, format)
_ca = append(_ca, v...)
_m.Called(_ca...)
}
// mockGoLogger_Printf_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Printf'
type mockGoLogger_Printf_Call struct {
*mock.Call
}
// Printf is a helper method to define mock.On call
// - format string
// - v ...interface{}
func (_e *mockGoLogger_Expecter) Printf(format interface{}, v ...interface{}) *mockGoLogger_Printf_Call {
return &mockGoLogger_Printf_Call{Call: _e.mock.On("Printf",
append([]interface{}{format}, v...)...)}
}
func (_c *mockGoLogger_Printf_Call) Run(run func(format string, v ...interface{})) *mockGoLogger_Printf_Call {
_c.Call.Run(func(args mock.Arguments) {
variadicArgs := make([]interface{}, len(args)-1)
for i, a := range args[1:] {
if a != nil {
variadicArgs[i] = a.(interface{})
}
}
run(args[0].(string), variadicArgs...)
})
return _c
}
func (_c *mockGoLogger_Printf_Call) Return() *mockGoLogger_Printf_Call {
_c.Call.Return()
return _c
}
type mockConstructorTestingTnewMockGoLogger interface {
mock.TestingT
Cleanup(func())
}
// newMockGoLogger creates a new instance of mockGoLogger. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func newMockGoLogger(t mockConstructorTestingTnewMockGoLogger) *mockGoLogger {
mock := &mockGoLogger{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@@ -1,121 +0,0 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
package mutex
import (
context "context"
mock "github.com/stretchr/testify/mock"
)
// MockInterface is an autogenerated mock type for the Interface type
type MockInterface struct {
mock.Mock
}
type MockInterface_Expecter struct {
mock *mock.Mock
}
func (_m *MockInterface) EXPECT() *MockInterface_Expecter {
return &MockInterface_Expecter{mock: &_m.Mock}
}
// Acquire provides a mock function with given fields: ctx, name
func (_m *MockInterface) Acquire(ctx context.Context, name string) (*Lock, error) {
ret := _m.Called(ctx, name)
var r0 *Lock
if rf, ok := ret.Get(0).(func(context.Context, string) *Lock); ok {
r0 = rf(ctx, name)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*Lock)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, name)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// MockInterface_Acquire_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Acquire'
type MockInterface_Acquire_Call struct {
*mock.Call
}
// Acquire is a helper method to define mock.On call
// - ctx context.Context
// - name string
func (_e *MockInterface_Expecter) Acquire(ctx interface{}, name interface{}) *MockInterface_Acquire_Call {
return &MockInterface_Acquire_Call{Call: _e.mock.On("Acquire", ctx, name)}
}
func (_c *MockInterface_Acquire_Call) Run(run func(ctx context.Context, name string)) *MockInterface_Acquire_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].(string))
})
return _c
}
func (_c *MockInterface_Acquire_Call) Return(_a0 *Lock, _a1 error) *MockInterface_Acquire_Call {
_c.Call.Return(_a0, _a1)
return _c
}
// Release provides a mock function with given fields: lock
func (_m *MockInterface) Release(lock *Lock) error {
ret := _m.Called(lock)
var r0 error
if rf, ok := ret.Get(0).(func(*Lock) error); ok {
r0 = rf(lock)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockInterface_Release_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Release'
type MockInterface_Release_Call struct {
*mock.Call
}
// Release is a helper method to define mock.On call
// - lock *Lock
func (_e *MockInterface_Expecter) Release(lock interface{}) *MockInterface_Release_Call {
return &MockInterface_Release_Call{Call: _e.mock.On("Release", lock)}
}
func (_c *MockInterface_Release_Call) Run(run func(lock *Lock)) *MockInterface_Release_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(*Lock))
})
return _c
}
func (_c *MockInterface_Release_Call) Return(_a0 error) *MockInterface_Release_Call {
_c.Call.Return(_a0)
return _c
}
type mockConstructorTestingTNewMockInterface interface {
mock.TestingT
Cleanup(func())
}
// NewMockInterface creates a new instance of MockInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func NewMockInterface(t mockConstructorTestingTNewMockInterface) *MockInterface {
mock := &MockInterface{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@@ -1,87 +0,0 @@
package mutex
import (
"context"
"fmt"
"os"
"path"
"github.com/alexflint/go-filemutex"
"github.com/google/wire"
"github.com/int128/kubelogin/pkg/infrastructure/logger"
)
var Set = wire.NewSet(
wire.Struct(new(Mutex), "*"),
wire.Bind(new(Interface), new(*Mutex)),
)
type Interface interface {
Acquire(ctx context.Context, name string) (*Lock, error)
Release(lock *Lock) error
}
// Lock holds the lock data.
type Lock struct {
Data interface{}
Name string
}
type Mutex struct {
Logger logger.Interface
}
// internalAcquire wait for acquisition of the lock
func internalAcquire(fm *filemutex.FileMutex) chan error {
result := make(chan error)
go func() {
if err := fm.Lock(); err != nil {
result <- err
}
close(result)
}()
return result
}
// internalRelease disposes of resources associated with a lock
func internalRelease(fm *filemutex.FileMutex, lfn string, log logger.Interface) error {
err := fm.Close()
if err != nil {
log.V(1).Infof("Error closing lock file %s: %s", lfn, err)
}
return err
}
// LockFileName get the lock file name from the lock name.
func LockFileName(name string) string {
return path.Join(os.TempDir(), fmt.Sprintf(".kubelogin.%s.lock", name))
}
// Acquire acquire a lock for the specified name. The context could be used to set a timeout.
func (m *Mutex) Acquire(ctx context.Context, name string) (*Lock, error) {
lfn := LockFileName(name)
fm, err := filemutex.New(lfn)
if err != nil {
return nil, fmt.Errorf("error creating mutex file %s: %w", lfn, err)
}
lockChan := internalAcquire(fm)
select {
case <-ctx.Done():
_ = internalRelease(fm, lfn, m.Logger)
return nil, ctx.Err()
case err := <-lockChan:
if err != nil {
_ = internalRelease(fm, lfn, m.Logger)
return nil, fmt.Errorf("error acquiring lock on file %s: %w", lfn, err)
}
return &Lock{Data: fm, Name: name}, nil
}
}
// Release release the specified lock
func (m *Mutex) Release(lock *Lock) error {
fm := lock.Data.(*filemutex.FileMutex)
lfn := LockFileName(lock.Name)
return internalRelease(fm, lfn, m.Logger)
}

View File

@@ -1,64 +0,0 @@
package mutex
import (
"fmt"
"github.com/int128/kubelogin/pkg/infrastructure/logger"
"golang.org/x/net/context"
"math/rand"
"sync"
"testing"
"time"
)
func TestMutex(t *testing.T) {
t.Run("Test successful parallel acquisition with no reentry allowed", func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
nbConcurrency := 20
wg := sync.WaitGroup{}
events := make(chan int, nbConcurrency*2)
errors := make(chan error, nbConcurrency)
doLockUnlock := func() {
defer wg.Done()
m := Mutex{
Logger: logger.New(),
}
if mutex, err := m.Acquire(ctx, "test"); err == nil {
events <- 1
var dur = time.Duration(rand.Intn(5000))
time.Sleep(dur * time.Microsecond)
events <- -1
if err := m.Release(mutex); err != nil {
errors <- fmt.Errorf("Release error: %w", err)
}
} else {
errors <- fmt.Errorf("Acquire error: %w", err)
}
}
for i := 0; i < nbConcurrency; i++ {
wg.Add(1)
go doLockUnlock()
}
wg.Wait()
close(events)
close(errors)
countConcurrent := 0
for delta := range events {
countConcurrent += delta
if countConcurrent > 1 {
t.Errorf("The mutex did not prevented reentry: %d", countConcurrent)
}
}
for anError := range errors {
t.Errorf("The gorouting returned an error: %s", anError)
}
})
}

View File

@@ -1,3 +0,0 @@
package pkg
//go:generate mockery --all --inpackage --with-expecter

View File

@@ -62,6 +62,7 @@ type client struct {
logger logger.Interface
supportedPKCEMethods []string
deviceAuthorizationEndpoint string
useAccessToken bool
}
func (c *client) wrapContext(ctx context.Context) context.Context {
@@ -205,6 +206,32 @@ func (c *client) verifyToken(ctx context.Context, token *oauth2.Token, nonce str
if nonce != "" && nonce != verifiedIDToken.Nonce {
return nil, fmt.Errorf("nonce did not match (wants %s but got %s)", nonce, verifiedIDToken.Nonce)
}
if c.useAccessToken {
accessToken, ok := token.Extra("access_token").(string)
if !ok {
return nil, fmt.Errorf("access_token is missing in the token response: %#v", accessToken)
}
// We intentionally do not perform a ClientID check here because there
// are some use cases in access_tokens where we *expect* the audience
// to differ. For example, one can explicitly set
// `audience=CLUSTER_CLIENT_ID` as an extra auth parameter.
verifier = c.provider.Verifier(&gooidc.Config{ClientID: "", Now: c.clock.Now, SkipClientIDCheck: true})
_, err := verifier.Verify(ctx, accessToken)
if err != nil {
return nil, fmt.Errorf("could not verify the access token: %w", err)
}
// There is no `nonce` to check on the `access_token`. We rely on the
// above `nonce` check on the `id_token`.
return &oidc.TokenSet{
IDToken: accessToken,
RefreshToken: token.RefreshToken,
}, nil
}
return &oidc.TokenSet{
IDToken: idToken,
RefreshToken: token.RefreshToken,

View File

@@ -80,6 +80,7 @@ func (f *Factory) New(ctx context.Context, p oidc.Provider, tlsClientConfig tlsc
logger: f.Logger,
supportedPKCEMethods: supportedPKCEMethods,
deviceAuthorizationEndpoint: deviceAuthorizationEndpoint,
useAccessToken: p.UseAccessToken,
}, nil
}

View File

@@ -11,11 +11,12 @@ import (
// Provider represents an OIDC provider.
type Provider struct {
IssuerURL string
ClientID string
ClientSecret string // optional
ExtraScopes []string // optional
UsePKCE bool // optional
IssuerURL string
ClientID string
ClientSecret string // optional
ExtraScopes []string // optional
UsePKCE bool // optional
UseAccessToken bool // optional
}
// TokenSet represents a set of ID token and refresh token.

View File

@@ -1,72 +0,0 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
package logger
import mock "github.com/stretchr/testify/mock"
// mockTestingLogger is an autogenerated mock type for the testingLogger type
type mockTestingLogger struct {
mock.Mock
}
type mockTestingLogger_Expecter struct {
mock *mock.Mock
}
func (_m *mockTestingLogger) EXPECT() *mockTestingLogger_Expecter {
return &mockTestingLogger_Expecter{mock: &_m.Mock}
}
// Logf provides a mock function with given fields: format, v
func (_m *mockTestingLogger) Logf(format string, v ...interface{}) {
var _ca []interface{}
_ca = append(_ca, format)
_ca = append(_ca, v...)
_m.Called(_ca...)
}
// mockTestingLogger_Logf_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Logf'
type mockTestingLogger_Logf_Call struct {
*mock.Call
}
// Logf is a helper method to define mock.On call
// - format string
// - v ...interface{}
func (_e *mockTestingLogger_Expecter) Logf(format interface{}, v ...interface{}) *mockTestingLogger_Logf_Call {
return &mockTestingLogger_Logf_Call{Call: _e.mock.On("Logf",
append([]interface{}{format}, v...)...)}
}
func (_c *mockTestingLogger_Logf_Call) Run(run func(format string, v ...interface{})) *mockTestingLogger_Logf_Call {
_c.Call.Run(func(args mock.Arguments) {
variadicArgs := make([]interface{}, len(args)-1)
for i, a := range args[1:] {
if a != nil {
variadicArgs[i] = a.(interface{})
}
}
run(args[0].(string), variadicArgs...)
})
return _c
}
func (_c *mockTestingLogger_Logf_Call) Return() *mockTestingLogger_Logf_Call {
_c.Call.Return()
return _c
}
type mockConstructorTestingTnewMockTestingLogger interface {
mock.TestingT
Cleanup(func())
}
// newMockTestingLogger creates a new instance of mockTestingLogger. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
func newMockTestingLogger(t mockConstructorTestingTnewMockTestingLogger) *mockTestingLogger {
mock := &mockTestingLogger{}
mock.Mock.Test(t)
t.Cleanup(func() { mock.AssertExpectations(t) })
return mock
}

View File

@@ -6,9 +6,11 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"
"github.com/gofrs/flock"
"github.com/google/wire"
"github.com/int128/kubelogin/pkg/oidc"
"github.com/int128/kubelogin/pkg/tokencache"
@@ -23,6 +25,7 @@ var Set = wire.NewSet(
type Interface interface {
FindByKey(dir string, key tokencache.Key) (*oidc.TokenSet, error)
Save(dir string, key tokencache.Key, tokenSet oidc.TokenSet) error
Lock(dir string, key tokencache.Key) (io.Closer, error)
}
type entity struct {
@@ -80,6 +83,24 @@ func (r *Repository) Save(dir string, key tokencache.Key, tokenSet oidc.TokenSet
return nil
}
func (r *Repository) Lock(tokenCacheDir string, key tokencache.Key) (io.Closer, error) {
if err := os.MkdirAll(tokenCacheDir, 0700); err != nil {
return nil, fmt.Errorf("could not create directory %s: %w", tokenCacheDir, err)
}
keyDigest, err := computeFilename(key)
if err != nil {
return nil, fmt.Errorf("could not compute the key: %w", err)
}
// Do not lock the token cache file.
// https://github.com/int128/kubelogin/issues/1144
lockFilepath := filepath.Join(tokenCacheDir, keyDigest+".lock")
lockFile := flock.New(lockFilepath)
if err := lockFile.Lock(); err != nil {
return nil, fmt.Errorf("could not lock the cache file %s: %w", lockFilepath, err)
}
return lockFile, nil
}
func computeFilename(key tokencache.Key) (string, error) {
s := sha256.New()
e := gob.NewEncoder(s)

View File

@@ -7,6 +7,7 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/int128/kubelogin/pkg/oidc"
"github.com/int128/kubelogin/pkg/tlsclientconfig"
"github.com/int128/kubelogin/pkg/tokencache"
)
@@ -16,12 +17,15 @@ func TestRepository_FindByKey(t *testing.T) {
t.Run("Success", func(t *testing.T) {
dir := t.TempDir()
key := tokencache.Key{
IssuerURL: "YOUR_ISSUER",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
ExtraScopes: []string{"openid", "email"},
CACertFilename: "/path/to/cert",
SkipTLSVerify: false,
Provider: oidc.Provider{
IssuerURL: "YOUR_ISSUER",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
ExtraScopes: []string{"openid", "email"},
},
TLSClientConfig: tlsclientconfig.Config{
CACertFilename: []string{"/path/to/cert"},
},
}
json := `{"id_token":"YOUR_ID_TOKEN","refresh_token":"YOUR_REFRESH_TOKEN"}`
filename, err := computeFilename(key)
@@ -50,12 +54,15 @@ func TestRepository_Save(t *testing.T) {
t.Run("Success", func(t *testing.T) {
dir := t.TempDir()
key := tokencache.Key{
IssuerURL: "YOUR_ISSUER",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
ExtraScopes: []string{"openid", "email"},
CACertFilename: "/path/to/cert",
SkipTLSVerify: false,
Provider: oidc.Provider{
IssuerURL: "YOUR_ISSUER",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
ExtraScopes: []string{"openid", "email"},
},
TLSClientConfig: tlsclientconfig.Config{
CACertFilename: []string{"/path/to/cert"},
},
}
tokenSet := oidc.TokenSet{IDToken: "YOUR_ID_TOKEN", RefreshToken: "YOUR_REFRESH_TOKEN"}
if err := r.Save(dir, key, tokenSet); err != nil {

View File

@@ -1,13 +1,13 @@
package tokencache
import (
"github.com/int128/kubelogin/pkg/oidc"
"github.com/int128/kubelogin/pkg/tlsclientconfig"
)
// Key represents a key of a token cache.
type Key struct {
IssuerURL string
ClientID string
ClientSecret string
Username string
ExtraScopes []string
CACertFilename string
CACertData string
SkipTLSVerify bool
Provider oidc.Provider
TLSClientConfig tlsclientconfig.Config
Username string
}

View File

@@ -6,7 +6,8 @@ import (
"time"
"github.com/google/go-cmp/cmp"
"github.com/int128/kubelogin/pkg/infrastructure/browser"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/infrastructure/browser_mock"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/oidc/client_mock"
"github.com/int128/kubelogin/pkg/oidc"
"github.com/int128/kubelogin/pkg/oidc/client"
"github.com/int128/kubelogin/pkg/testing/logger"
@@ -29,7 +30,7 @@ func TestBrowser_Do(t *testing.T) {
RedirectURLHostname: "localhost",
AuthRequestExtraParams: map[string]string{"ttl": "86400", "reauth": "true"},
}
mockClient := client.NewMockInterface(t)
mockClient := client_mock.NewMockInterface(t)
mockClient.EXPECT().
SupportedPKCEMethods().
Return(nil)
@@ -83,7 +84,7 @@ func TestBrowser_Do(t *testing.T) {
BindAddress: []string{"127.0.0.1:8000"},
AuthenticationTimeout: 10 * time.Second,
}
mockClient := client.NewMockInterface(t)
mockClient := client_mock.NewMockInterface(t)
mockClient.EXPECT().
SupportedPKCEMethods().
Return(nil)
@@ -96,7 +97,7 @@ func TestBrowser_Do(t *testing.T) {
IDToken: "YOUR_ID_TOKEN",
RefreshToken: "YOUR_REFRESH_TOKEN",
}, nil)
mockBrowser := browser.NewMockInterface(t)
mockBrowser := browser_mock.NewMockInterface(t)
mockBrowser.EXPECT().
Open("LOCAL_SERVER_URL").
Return(nil)
@@ -125,7 +126,7 @@ func TestBrowser_Do(t *testing.T) {
BrowserCommand: "firefox",
AuthenticationTimeout: 10 * time.Second,
}
mockClient := client.NewMockInterface(t)
mockClient := client_mock.NewMockInterface(t)
mockClient.EXPECT().
SupportedPKCEMethods().
Return(nil)
@@ -138,7 +139,7 @@ func TestBrowser_Do(t *testing.T) {
IDToken: "YOUR_ID_TOKEN",
RefreshToken: "YOUR_REFRESH_TOKEN",
}, nil)
mockBrowser := browser.NewMockInterface(t)
mockBrowser := browser_mock.NewMockInterface(t)
mockBrowser.EXPECT().
OpenCommand(mock.Anything, "LOCAL_SERVER_URL", "firefox").
Return(nil)

View File

@@ -6,7 +6,8 @@ import (
"time"
"github.com/google/go-cmp/cmp"
"github.com/int128/kubelogin/pkg/infrastructure/reader"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/infrastructure/reader_mock"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/oidc/client_mock"
"github.com/int128/kubelogin/pkg/oidc"
"github.com/int128/kubelogin/pkg/oidc/client"
"github.com/int128/kubelogin/pkg/testing/logger"
@@ -22,7 +23,7 @@ func TestKeyboard_Do(t *testing.T) {
o := &KeyboardOption{
AuthRequestExtraParams: map[string]string{"ttl": "86400", "reauth": "true"},
}
mockClient := client.NewMockInterface(t)
mockClient := client_mock.NewMockInterface(t)
mockClient.EXPECT().
SupportedPKCEMethods().
Return(nil)
@@ -45,7 +46,7 @@ func TestKeyboard_Do(t *testing.T) {
IDToken: "YOUR_ID_TOKEN",
RefreshToken: "YOUR_REFRESH_TOKEN",
}, nil)
mockReader := reader.NewMockInterface(t)
mockReader := reader_mock.NewMockInterface(t)
mockReader.EXPECT().
ReadString(keyboardPrompt).
Return("YOUR_AUTH_CODE", nil)

View File

@@ -5,7 +5,6 @@ import (
"fmt"
"github.com/google/wire"
"github.com/int128/kubelogin/pkg/infrastructure/clock"
"github.com/int128/kubelogin/pkg/infrastructure/logger"
"github.com/int128/kubelogin/pkg/oidc"
"github.com/int128/kubelogin/pkg/oidc/client"
@@ -36,6 +35,7 @@ type Input struct {
CachedTokenSet *oidc.TokenSet // optional
TLSClientConfig tlsclientconfig.Config
ForceRefresh bool
UseAccessToken bool
}
type GrantOptionSet struct {
@@ -47,8 +47,7 @@ type GrantOptionSet struct {
// Output represents an output DTO of the Authentication use-case.
type Output struct {
AlreadyHasValidIDToken bool
TokenSet oidc.TokenSet
TokenSet oidc.TokenSet
}
// Authentication provides the internal use-case of authentication.
@@ -66,7 +65,6 @@ type Output struct {
type Authentication struct {
ClientFactory client.FactoryInterface
Logger logger.Interface
Clock clock.Interface
AuthCodeBrowser *authcode.Browser
AuthCodeKeyboard *authcode.Keyboard
ROPC *ropc.ROPC
@@ -74,29 +72,6 @@ type Authentication struct {
}
func (u *Authentication) Do(ctx context.Context, in Input) (*Output, error) {
if in.CachedTokenSet != nil {
if in.ForceRefresh {
u.Logger.V(1).Infof("forcing refresh of the existing token")
} else {
u.Logger.V(1).Infof("checking expiration of the existing token")
// Skip verification of the token to reduce time of a discovery request.
// Here it trusts the signature and claims and checks only expiration,
// because the token has been verified before caching.
claims, err := in.CachedTokenSet.DecodeWithoutVerify()
if err != nil {
return nil, fmt.Errorf("invalid token cache (you may need to remove): %w", err)
}
if !claims.IsExpired(u.Clock) {
u.Logger.V(1).Infof("you already have a valid token until %s", claims.Expiry)
return &Output{
AlreadyHasValidIDToken: true,
TokenSet: *in.CachedTokenSet,
}, nil
}
u.Logger.V(1).Infof("you have an expired token at %s", claims.Expiry)
}
}
u.Logger.V(1).Infof("initializing an OpenID Connect client")
oidcClient, err := u.ClientFactory.New(ctx, in.Provider, in.TLSClientConfig)
if err != nil {

View File

@@ -8,9 +8,9 @@ import (
"github.com/golang-jwt/jwt/v5"
"github.com/google/go-cmp/cmp"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/oidc/client_mock"
"github.com/int128/kubelogin/pkg/oidc"
"github.com/int128/kubelogin/pkg/oidc/client"
"github.com/int128/kubelogin/pkg/testing/clock"
testingJWT "github.com/int128/kubelogin/pkg/testing/jwt"
testingLogger "github.com/int128/kubelogin/pkg/testing/logger"
"github.com/int128/kubelogin/pkg/tlsclientconfig"
@@ -36,35 +36,6 @@ func TestAuthentication_Do(t *testing.T) {
claims.ExpiresAt = jwt.NewNumericDate(expiryTime)
})
t.Run("HasValidIDToken", func(t *testing.T) {
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
in := Input{
Provider: dummyProvider,
TLSClientConfig: dummyTLSClientConfig,
CachedTokenSet: &oidc.TokenSet{
IDToken: issuedIDToken,
},
}
u := Authentication{
Logger: testingLogger.New(t),
Clock: clock.Fake(expiryTime.Add(-time.Hour)),
}
got, err := u.Do(ctx, in)
if err != nil {
t.Errorf("Do returned error: %+v", err)
}
want := &Output{
AlreadyHasValidIDToken: true,
TokenSet: oidc.TokenSet{
IDToken: issuedIDToken,
},
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("mismatch (-want +got):\n%s", diff)
}
})
t.Run("HasValidRefreshToken", func(t *testing.T) {
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
@@ -76,21 +47,20 @@ func TestAuthentication_Do(t *testing.T) {
RefreshToken: "VALID_REFRESH_TOKEN",
},
}
mockClient := client.NewMockInterface(t)
mockClient := client_mock.NewMockInterface(t)
mockClient.EXPECT().
Refresh(ctx, "VALID_REFRESH_TOKEN").
Return(&oidc.TokenSet{
IDToken: "NEW_ID_TOKEN",
RefreshToken: "NEW_REFRESH_TOKEN",
}, nil)
mockClientFactory := client.NewMockFactoryInterface(t)
mockClientFactory := client_mock.NewMockFactoryInterface(t)
mockClientFactory.EXPECT().
New(ctx, dummyProvider, dummyTLSClientConfig).
Return(mockClient, nil)
u := Authentication{
ClientFactory: mockClientFactory,
Logger: testingLogger.New(t),
Clock: clock.Fake(expiryTime.Add(+time.Hour)),
}
got, err := u.Do(ctx, in)
if err != nil {
@@ -125,7 +95,7 @@ func TestAuthentication_Do(t *testing.T) {
RefreshToken: "EXPIRED_REFRESH_TOKEN",
},
}
mockClient := client.NewMockInterface(t)
mockClient := client_mock.NewMockInterface(t)
mockClient.EXPECT().
SupportedPKCEMethods().
Return(nil)
@@ -141,14 +111,13 @@ func TestAuthentication_Do(t *testing.T) {
IDToken: "NEW_ID_TOKEN",
RefreshToken: "NEW_REFRESH_TOKEN",
}, nil)
mockClientFactory := client.NewMockFactoryInterface(t)
mockClientFactory := client_mock.NewMockFactoryInterface(t)
mockClientFactory.EXPECT().
New(ctx, dummyProvider, dummyTLSClientConfig).
Return(mockClient, nil)
u := Authentication{
ClientFactory: mockClientFactory,
Logger: testingLogger.New(t),
Clock: clock.Fake(expiryTime.Add(+time.Hour)),
AuthCodeBrowser: &authcode.Browser{
Logger: testingLogger.New(t),
},
@@ -181,14 +150,14 @@ func TestAuthentication_Do(t *testing.T) {
},
},
}
mockClient := client.NewMockInterface(t)
mockClient := client_mock.NewMockInterface(t)
mockClient.EXPECT().
GetTokenByROPC(mock.Anything, "USER", "PASS").
Return(&oidc.TokenSet{
IDToken: "YOUR_ID_TOKEN",
RefreshToken: "YOUR_REFRESH_TOKEN",
}, nil)
mockClientFactory := client.NewMockFactoryInterface(t)
mockClientFactory := client_mock.NewMockFactoryInterface(t)
mockClientFactory.EXPECT().
New(ctx, dummyProvider, dummyTLSClientConfig).
Return(mockClient, nil)

View File

@@ -5,9 +5,9 @@ import (
"errors"
"testing"
"github.com/int128/kubelogin/pkg/infrastructure/browser"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/infrastructure/browser_mock"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/oidc/client_mock"
"github.com/int128/kubelogin/pkg/oidc"
"github.com/int128/kubelogin/pkg/oidc/client"
"github.com/int128/kubelogin/pkg/testing/logger"
"github.com/int128/oauth2dev"
"github.com/stretchr/testify/mock"
@@ -17,9 +17,9 @@ func TestDeviceCode(t *testing.T) {
ctx := context.TODO()
t.Run("Authorization error", func(t *testing.T) {
mockClient := client.NewMockInterface(t)
mockClient := client_mock.NewMockInterface(t)
dc := &DeviceCode{
Browser: browser.NewMockInterface(t),
Browser: browser_mock.NewMockInterface(t),
Logger: logger.New(t),
}
errTest := errors.New("test error")
@@ -31,8 +31,8 @@ func TestDeviceCode(t *testing.T) {
})
t.Run("Server returns verification_uri_complete", func(t *testing.T) {
mockBrowser := browser.NewMockInterface(t)
mockClient := client.NewMockInterface(t)
mockBrowser := browser_mock.NewMockInterface(t)
mockClient := client_mock.NewMockInterface(t)
dc := &DeviceCode{
Browser: mockBrowser,
Logger: logger.New(t),
@@ -63,8 +63,8 @@ func TestDeviceCode(t *testing.T) {
})
t.Run("Server returns verification_uri", func(t *testing.T) {
mockBrowser := browser.NewMockInterface(t)
mockClient := client.NewMockInterface(t)
mockBrowser := browser_mock.NewMockInterface(t)
mockClient := client_mock.NewMockInterface(t)
dc := &DeviceCode{
Browser: mockBrowser,
Logger: logger.New(t),
@@ -95,8 +95,8 @@ func TestDeviceCode(t *testing.T) {
})
t.Run("Server returns verification_url", func(t *testing.T) {
mockBrowser := browser.NewMockInterface(t)
mockClient := client.NewMockInterface(t)
mockBrowser := browser_mock.NewMockInterface(t)
mockClient := client_mock.NewMockInterface(t)
dc := &DeviceCode{
Browser: mockBrowser,
Logger: logger.New(t),
@@ -122,8 +122,8 @@ func TestDeviceCode(t *testing.T) {
})
t.Run("Error when exchanging the device code", func(t *testing.T) {
mockBrowser := browser.NewMockInterface(t)
mockClient := client.NewMockInterface(t)
mockBrowser := browser_mock.NewMockInterface(t)
mockClient := client_mock.NewMockInterface(t)
dc := &DeviceCode{
Browser: mockBrowser,
Logger: logger.New(t),
@@ -155,7 +155,7 @@ func TestDeviceCode_openURL(t *testing.T) {
var testError = errors.New("test error")
t.Run("Continue if error opening the browser", func(t *testing.T) {
browserMock := browser.NewMockInterface(t)
browserMock := browser_mock.NewMockInterface(t)
deviceCode := &DeviceCode{
Browser: browserMock,
Logger: logger.New(t),
@@ -165,7 +165,7 @@ func TestDeviceCode_openURL(t *testing.T) {
})
t.Run("SkipOpenBrowser is set", func(t *testing.T) {
browserMock := browser.NewMockInterface(t)
browserMock := browser_mock.NewMockInterface(t)
deviceCode := &DeviceCode{
Browser: browserMock,
Logger: logger.New(t),
@@ -174,7 +174,7 @@ func TestDeviceCode_openURL(t *testing.T) {
})
t.Run("BrowserCommand is set", func(t *testing.T) {
browserMock := browser.NewMockInterface(t)
browserMock := browser_mock.NewMockInterface(t)
deviceCode := &DeviceCode{
Browser: browserMock,
Logger: logger.New(t),

View File

@@ -7,9 +7,9 @@ import (
"time"
"github.com/google/go-cmp/cmp"
"github.com/int128/kubelogin/pkg/infrastructure/reader"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/infrastructure/reader_mock"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/oidc/client_mock"
"github.com/int128/kubelogin/pkg/oidc"
"github.com/int128/kubelogin/pkg/oidc/client"
"github.com/int128/kubelogin/pkg/testing/logger"
"github.com/stretchr/testify/mock"
)
@@ -21,14 +21,14 @@ func TestROPC_Do(t *testing.T) {
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
o := &Option{}
mockClient := client.NewMockInterface(t)
mockClient := client_mock.NewMockInterface(t)
mockClient.EXPECT().
GetTokenByROPC(mock.Anything, "USER", "PASS").
Return(&oidc.TokenSet{
IDToken: "YOUR_ID_TOKEN",
RefreshToken: "YOUR_REFRESH_TOKEN",
}, nil)
mockReader := reader.NewMockInterface(t)
mockReader := reader_mock.NewMockInterface(t)
mockReader.EXPECT().ReadString(usernamePrompt).Return("USER", nil)
mockReader.EXPECT().ReadPassword(passwordPrompt).Return("PASS", nil)
u := ROPC{
@@ -55,7 +55,7 @@ func TestROPC_Do(t *testing.T) {
Username: "USER",
Password: "PASS",
}
mockClient := client.NewMockInterface(t)
mockClient := client_mock.NewMockInterface(t)
mockClient.EXPECT().
GetTokenByROPC(mock.Anything, "USER", "PASS").
Return(&oidc.TokenSet{
@@ -84,14 +84,14 @@ func TestROPC_Do(t *testing.T) {
o := &Option{
Username: "USER",
}
mockClient := client.NewMockInterface(t)
mockClient := client_mock.NewMockInterface(t)
mockClient.EXPECT().
GetTokenByROPC(mock.Anything, "USER", "PASS").
Return(&oidc.TokenSet{
IDToken: "YOUR_ID_TOKEN",
RefreshToken: "YOUR_REFRESH_TOKEN",
}, nil)
mockEnv := reader.NewMockInterface(t)
mockEnv := reader_mock.NewMockInterface(t)
mockEnv.EXPECT().ReadPassword(passwordPrompt).Return("PASS", nil)
u := ROPC{
Reader: mockEnv,
@@ -116,13 +116,13 @@ func TestROPC_Do(t *testing.T) {
o := &Option{
Username: "USER",
}
mockEnv := reader.NewMockInterface(t)
mockEnv := reader_mock.NewMockInterface(t)
mockEnv.EXPECT().ReadPassword(passwordPrompt).Return("", errors.New("error"))
u := ROPC{
Reader: mockEnv,
Logger: logger.New(t),
}
out, err := u.Do(ctx, o, client.NewMockInterface(t))
out, err := u.Do(ctx, o, client_mock.NewMockInterface(t))
if err == nil {
t.Errorf("err wants non-nil but nil")
}

View File

@@ -6,20 +6,18 @@ package credentialplugin
import (
"context"
"fmt"
"net"
"strings"
"github.com/google/wire"
"github.com/int128/kubelogin/pkg/credentialplugin"
"github.com/int128/kubelogin/pkg/credentialplugin/writer"
credentialpluginreader "github.com/int128/kubelogin/pkg/credentialplugin/reader"
credentialpluginwriter "github.com/int128/kubelogin/pkg/credentialplugin/writer"
"github.com/int128/kubelogin/pkg/infrastructure/clock"
"github.com/int128/kubelogin/pkg/infrastructure/logger"
"github.com/int128/kubelogin/pkg/infrastructure/mutex"
"github.com/int128/kubelogin/pkg/oidc"
"github.com/int128/kubelogin/pkg/tlsclientconfig"
"github.com/int128/kubelogin/pkg/tokencache"
"github.com/int128/kubelogin/pkg/tokencache/repository"
"github.com/int128/kubelogin/pkg/usecases/authentication"
"github.com/int128/kubelogin/pkg/usecases/authentication/authcode"
)
var Set = wire.NewSet(
@@ -41,50 +39,75 @@ type Input struct {
}
type GetToken struct {
Authentication authentication.Interface
TokenCacheRepository repository.Interface
Writer writer.Interface
Mutex mutex.Interface
Logger logger.Interface
Authentication authentication.Interface
TokenCacheRepository repository.Interface
CredentialPluginReader credentialpluginreader.Interface
CredentialPluginWriter credentialpluginwriter.Interface
Logger logger.Interface
Clock clock.Interface
}
func (u *GetToken) Do(ctx context.Context, in Input) error {
u.Logger.V(1).Infof("WARNING: log may contain your secrets such as token or password")
// Prevent multiple concurrent port binding using a file mutex.
// See https://github.com/int128/kubelogin/issues/389
bindPorts := extractBindAddressPorts(in.GrantOptionSet.AuthCodeBrowserOption)
if bindPorts != nil {
key := fmt.Sprintf("get-token-%s", strings.Join(bindPorts, "-"))
u.Logger.V(1).Infof("acquiring a lock %s", key)
lock, err := u.Mutex.Acquire(ctx, key)
if err != nil {
return fmt.Errorf("could not acquire a lock: %w", err)
}
defer func() {
if err := u.Mutex.Release(lock); err != nil {
u.Logger.V(1).Infof("could not release the lock: %s", err)
}
}()
credentialPluginInput, err := u.CredentialPluginReader.Read()
if err != nil {
return fmt.Errorf("could not read the input of credential plugin: %w", err)
}
u.Logger.V(1).Infof("credential plugin is called with apiVersion: %s", credentialPluginInput.ClientAuthenticationAPIVersion)
u.Logger.V(1).Infof("finding a token from cache directory %s", in.TokenCacheDir)
tokenCacheKey := tokencache.Key{
IssuerURL: in.Provider.IssuerURL,
ClientID: in.Provider.ClientID,
ClientSecret: in.Provider.ClientSecret,
ExtraScopes: in.Provider.ExtraScopes,
CACertFilename: strings.Join(in.TLSClientConfig.CACertFilename, ","),
CACertData: strings.Join(in.TLSClientConfig.CACertData, ","),
SkipTLSVerify: in.TLSClientConfig.SkipTLSVerify,
Provider: in.Provider,
TLSClientConfig: in.TLSClientConfig,
}
if in.GrantOptionSet.ROPCOption != nil {
tokenCacheKey.Username = in.GrantOptionSet.ROPCOption.Username
}
u.Logger.V(1).Infof("acquiring the lock of token cache")
lock, err := u.TokenCacheRepository.Lock(in.TokenCacheDir, tokenCacheKey)
if err != nil {
return fmt.Errorf("could not lock the token cache: %w", err)
}
defer func() {
u.Logger.V(1).Infof("releasing the lock of token cache")
if err := lock.Close(); err != nil {
u.Logger.Printf("could not unlock the token cache: %s", err)
}
}()
cachedTokenSet, err := u.TokenCacheRepository.FindByKey(in.TokenCacheDir, tokenCacheKey)
if err != nil {
u.Logger.V(1).Infof("could not find a token cache: %s", err)
}
if cachedTokenSet != nil {
if in.ForceRefresh {
u.Logger.V(1).Infof("forcing refresh of the existing token")
} else {
u.Logger.V(1).Infof("checking expiration of the existing token")
// Skip verification of the token to reduce time of a discovery request.
// Here it trusts the signature and claims and checks only expiration,
// because the token has been verified before caching.
claims, err := cachedTokenSet.DecodeWithoutVerify()
if err != nil {
return fmt.Errorf("invalid token cache (you may need to remove): %w", err)
}
if !claims.IsExpired(u.Clock) {
u.Logger.V(1).Infof("you already have a valid token until %s", claims.Expiry)
out := credentialplugin.Output{
Token: cachedTokenSet.IDToken,
Expiry: claims.Expiry,
ClientAuthenticationAPIVersion: credentialPluginInput.ClientAuthenticationAPIVersion,
}
if err := u.CredentialPluginWriter.Write(out); err != nil {
return fmt.Errorf("could not write the token to client-go: %w", err)
}
return nil
}
u.Logger.V(1).Infof("you have an expired token at %s", claims.Expiry)
}
}
authenticationInput := authentication.Input{
Provider: in.Provider,
@@ -102,40 +125,18 @@ func (u *GetToken) Do(ctx context.Context, in Input) error {
return fmt.Errorf("you got an invalid token: %w", err)
}
u.Logger.V(1).Infof("you got a token: %s", idTokenClaims.Pretty)
if authenticationOutput.AlreadyHasValidIDToken {
u.Logger.V(1).Infof("you already have a valid token until %s", idTokenClaims.Expiry)
} else {
u.Logger.V(1).Infof("you got a valid token until %s", idTokenClaims.Expiry)
if err := u.TokenCacheRepository.Save(in.TokenCacheDir, tokenCacheKey, authenticationOutput.TokenSet); err != nil {
return fmt.Errorf("could not write the token cache: %w", err)
}
u.Logger.V(1).Infof("you got a valid token until %s", idTokenClaims.Expiry)
if err := u.TokenCacheRepository.Save(in.TokenCacheDir, tokenCacheKey, authenticationOutput.TokenSet); err != nil {
return fmt.Errorf("could not write the token cache: %w", err)
}
u.Logger.V(1).Infof("writing the token to client-go")
out := credentialplugin.Output{
Token: authenticationOutput.TokenSet.IDToken,
Expiry: idTokenClaims.Expiry,
Token: authenticationOutput.TokenSet.IDToken,
Expiry: idTokenClaims.Expiry,
ClientAuthenticationAPIVersion: credentialPluginInput.ClientAuthenticationAPIVersion,
}
if err := u.Writer.Write(out); err != nil {
if err := u.CredentialPluginWriter.Write(out); err != nil {
return fmt.Errorf("could not write the token to client-go: %w", err)
}
return nil
}
func extractBindAddressPorts(o *authcode.BrowserOption) []string {
if o == nil {
return nil
}
var ports []string
for _, addr := range o.BindAddress {
_, port, err := net.SplitHostPort(addr)
if err != nil {
return nil // invalid address
}
if port == "0" {
return nil // any port
}
ports = append(ports, port)
}
return ports
}

View File

@@ -7,10 +7,13 @@ import (
"time"
"github.com/golang-jwt/jwt/v5"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/credentialplugin/reader_mock"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/credentialplugin/writer_mock"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/tokencache/repository_mock"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/usecases/authentication_mock"
"github.com/int128/kubelogin/mocks/io_mock"
"github.com/int128/kubelogin/pkg/credentialplugin"
"github.com/int128/kubelogin/pkg/credentialplugin/writer"
"github.com/int128/kubelogin/pkg/infrastructure/mutex"
"github.com/int128/kubelogin/pkg/tokencache/repository"
"github.com/int128/kubelogin/pkg/testing/clock"
"github.com/int128/kubelogin/pkg/usecases/authentication/authcode"
"github.com/int128/kubelogin/pkg/oidc"
@@ -27,19 +30,23 @@ func TestGetToken_Do(t *testing.T) {
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
}
issuedIDTokenExpiration := time.Now().Add(1 * time.Hour).Round(time.Second)
expiryTime := time.Date(2020, 1, 2, 3, 4, 5, 0, time.UTC).Local()
issuedIDToken := testingJWT.EncodeF(t, func(claims *testingJWT.Claims) {
claims.Issuer = "https://accounts.google.com"
claims.Subject = "YOUR_SUBJECT"
claims.ExpiresAt = jwt.NewNumericDate(issuedIDTokenExpiration)
claims.ExpiresAt = jwt.NewNumericDate(expiryTime)
})
issuedTokenSet := oidc.TokenSet{
IDToken: issuedIDToken,
RefreshToken: "YOUR_REFRESH_TOKEN",
}
issuedOutput := credentialplugin.Output{
Token: issuedIDToken,
Expiry: issuedIDTokenExpiration,
Token: issuedIDToken,
Expiry: expiryTime,
ClientAuthenticationAPIVersion: "client.authentication.k8s.io/v1",
}
credentialpluginInput := credentialplugin.Input{
ClientAuthenticationAPIVersion: "client.authentication.k8s.io/v1",
}
grantOptionSet := authentication.GrantOptionSet{
AuthCodeBrowserOption: &authcode.BrowserOption{
@@ -49,95 +56,54 @@ func TestGetToken_Do(t *testing.T) {
t.Run("NoTokenCache", func(t *testing.T) {
tokenCacheKey := tokencache.Key{
IssuerURL: "https://accounts.google.com",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
}
ctx := context.TODO()
in := Input{
Provider: dummyProvider,
TokenCacheDir: "/path/to/token-cache",
GrantOptionSet: grantOptionSet,
}
mockAuthentication := authentication.NewMockInterface(t)
mockAuthentication.EXPECT().
Do(ctx, authentication.Input{
Provider: dummyProvider,
GrantOptionSet: grantOptionSet,
}).
Return(&authentication.Output{TokenSet: issuedTokenSet}, nil)
mockRepository := repository.NewMockInterface(t)
mockRepository.EXPECT().
FindByKey("/path/to/token-cache", tokenCacheKey).
Return(nil, errors.New("file not found"))
mockRepository.EXPECT().
Save("/path/to/token-cache", tokenCacheKey, issuedTokenSet).
Return(nil)
mockWriter := writer.NewMockInterface(t)
mockWriter.EXPECT().
Write(issuedOutput).
Return(nil)
u := GetToken{
Authentication: mockAuthentication,
TokenCacheRepository: mockRepository,
Writer: mockWriter,
Mutex: mutex.NewMockInterface(t),
Logger: logger.New(t),
}
if err := u.Do(ctx, in); err != nil {
t.Errorf("Do returned error: %+v", err)
}
})
t.Run("NeedBindPortMutex", func(t *testing.T) {
grantOptionSet := authentication.GrantOptionSet{
AuthCodeBrowserOption: &authcode.BrowserOption{
BindAddress: []string{"127.0.0.1:8080"},
Provider: oidc.Provider{
IssuerURL: "https://accounts.google.com",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
},
}
tokenCacheKey := tokencache.Key{
IssuerURL: "https://accounts.google.com",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
}
ctx := context.TODO()
in := Input{
Provider: dummyProvider,
TokenCacheDir: "/path/to/token-cache",
GrantOptionSet: grantOptionSet,
}
mockAuthentication := authentication.NewMockInterface(t)
mockAuthentication := authentication_mock.NewMockInterface(t)
mockAuthentication.EXPECT().
Do(ctx, authentication.Input{
Provider: dummyProvider,
GrantOptionSet: grantOptionSet,
}).
Return(&authentication.Output{TokenSet: issuedTokenSet}, nil)
mockRepository := repository.NewMockInterface(t)
mockCloser := io_mock.NewMockCloser(t)
mockCloser.EXPECT().
Close().
Return(nil)
mockRepository := repository_mock.NewMockInterface(t)
mockRepository.EXPECT().
Lock("/path/to/token-cache", tokenCacheKey).
Return(mockCloser, nil)
mockRepository.EXPECT().
FindByKey("/path/to/token-cache", tokenCacheKey).
Return(nil, errors.New("file not found"))
mockRepository.EXPECT().
Save("/path/to/token-cache", tokenCacheKey, issuedTokenSet).
Return(nil)
mockWriter := writer.NewMockInterface(t)
mockReader := reader_mock.NewMockInterface(t)
mockReader.EXPECT().
Read().
Return(credentialpluginInput, nil)
mockWriter := writer_mock.NewMockInterface(t)
mockWriter.EXPECT().
Write(issuedOutput).
Return(nil)
mockMutex := mutex.NewMockInterface(t)
mockMutex.EXPECT().
Acquire(ctx, "get-token-8080").
Return(&mutex.Lock{Data: "testData"}, nil)
mockMutex.EXPECT().
Release(&mutex.Lock{Data: "testData"}).
Return(nil)
u := GetToken{
Authentication: mockAuthentication,
TokenCacheRepository: mockRepository,
Writer: mockWriter,
Mutex: mockMutex,
Logger: logger.New(t),
Authentication: mockAuthentication,
TokenCacheRepository: mockRepository,
CredentialPluginReader: mockReader,
CredentialPluginWriter: mockWriter,
Logger: logger.New(t),
Clock: clock.Fake(expiryTime.Add(-time.Hour)),
}
if err := u.Do(ctx, in); err != nil {
t.Errorf("Do returned error: %+v", err)
@@ -149,10 +115,12 @@ func TestGetToken_Do(t *testing.T) {
ROPCOption: &ropc.Option{Username: "YOUR_USERNAME"},
}
tokenCacheKey := tokencache.Key{
IssuerURL: "https://accounts.google.com",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
Username: "YOUR_USERNAME",
Provider: oidc.Provider{
IssuerURL: "https://accounts.google.com",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
},
Username: "YOUR_USERNAME",
}
ctx := context.TODO()
@@ -161,30 +129,42 @@ func TestGetToken_Do(t *testing.T) {
TokenCacheDir: "/path/to/token-cache",
GrantOptionSet: grantOptionSet,
}
mockAuthentication := authentication.NewMockInterface(t)
mockAuthentication := authentication_mock.NewMockInterface(t)
mockAuthentication.EXPECT().
Do(ctx, authentication.Input{
Provider: dummyProvider,
GrantOptionSet: grantOptionSet,
}).
Return(&authentication.Output{TokenSet: issuedTokenSet}, nil)
mockRepository := repository.NewMockInterface(t)
mockCloser := io_mock.NewMockCloser(t)
mockCloser.EXPECT().
Close().
Return(nil)
mockRepository := repository_mock.NewMockInterface(t)
mockRepository.EXPECT().
Lock("/path/to/token-cache", tokenCacheKey).
Return(mockCloser, nil)
mockRepository.EXPECT().
FindByKey("/path/to/token-cache", tokenCacheKey).
Return(nil, errors.New("file not found"))
mockRepository.EXPECT().
Save("/path/to/token-cache", tokenCacheKey, issuedTokenSet).
Return(nil)
mockWriter := writer.NewMockInterface(t)
mockReader := reader_mock.NewMockInterface(t)
mockReader.EXPECT().
Read().
Return(credentialplugin.Input{ClientAuthenticationAPIVersion: "client.authentication.k8s.io/v1"}, nil)
mockWriter := writer_mock.NewMockInterface(t)
mockWriter.EXPECT().
Write(issuedOutput).
Return(nil)
u := GetToken{
Authentication: mockAuthentication,
TokenCacheRepository: mockRepository,
Writer: mockWriter,
Mutex: mutex.NewMockInterface(t),
Logger: logger.New(t),
Authentication: mockAuthentication,
TokenCacheRepository: mockRepository,
CredentialPluginReader: mockReader,
CredentialPluginWriter: mockWriter,
Logger: logger.New(t),
Clock: clock.Fake(expiryTime.Add(-time.Hour)),
}
if err := u.Do(ctx, in); err != nil {
t.Errorf("Do returned error: %+v", err)
@@ -192,41 +172,52 @@ func TestGetToken_Do(t *testing.T) {
})
t.Run("HasValidIDToken", func(t *testing.T) {
tokenCacheKey := tokencache.Key{
Provider: oidc.Provider{
IssuerURL: "https://accounts.google.com",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
},
}
ctx := context.TODO()
in := Input{
Provider: dummyProvider,
TokenCacheDir: "/path/to/token-cache",
GrantOptionSet: grantOptionSet,
}
mockAuthentication := authentication.NewMockInterface(t)
mockAuthentication.EXPECT().
Do(ctx, authentication.Input{
Provider: dummyProvider,
CachedTokenSet: &issuedTokenSet,
GrantOptionSet: grantOptionSet,
}).
Return(&authentication.Output{
AlreadyHasValidIDToken: true,
TokenSet: issuedTokenSet,
}, nil)
mockRepository := repository.NewMockInterface(t)
mockCloser := io_mock.NewMockCloser(t)
mockCloser.EXPECT().
Close().
Return(nil)
mockRepository := repository_mock.NewMockInterface(t)
mockRepository.EXPECT().
Lock("/path/to/token-cache", tokenCacheKey).
Return(mockCloser, nil)
mockRepository.EXPECT().
FindByKey("/path/to/token-cache", tokencache.Key{
IssuerURL: "https://accounts.google.com",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
Provider: oidc.Provider{
IssuerURL: "https://accounts.google.com",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
},
}).
Return(&issuedTokenSet, nil)
mockWriter := writer.NewMockInterface(t)
mockReader := reader_mock.NewMockInterface(t)
mockReader.EXPECT().
Read().
Return(credentialpluginInput, nil)
mockWriter := writer_mock.NewMockInterface(t)
mockWriter.EXPECT().
Write(issuedOutput).
Return(nil)
u := GetToken{
Authentication: mockAuthentication,
TokenCacheRepository: mockRepository,
Writer: mockWriter,
Mutex: mutex.NewMockInterface(t),
Logger: logger.New(t),
Authentication: authentication_mock.NewMockInterface(t),
TokenCacheRepository: mockRepository,
CredentialPluginReader: mockReader,
CredentialPluginWriter: mockWriter,
Logger: logger.New(t),
Clock: clock.Fake(expiryTime.Add(-time.Hour)),
}
if err := u.Do(ctx, in); err != nil {
t.Errorf("Do returned error: %+v", err)
@@ -234,33 +225,54 @@ func TestGetToken_Do(t *testing.T) {
})
t.Run("AuthenticationError", func(t *testing.T) {
tokenCacheKey := tokencache.Key{
Provider: oidc.Provider{
IssuerURL: "https://accounts.google.com",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
},
}
ctx := context.TODO()
in := Input{
Provider: dummyProvider,
TokenCacheDir: "/path/to/token-cache",
GrantOptionSet: grantOptionSet,
}
mockAuthentication := authentication.NewMockInterface(t)
mockAuthentication := authentication_mock.NewMockInterface(t)
mockAuthentication.EXPECT().
Do(ctx, authentication.Input{
Provider: dummyProvider,
GrantOptionSet: grantOptionSet,
}).
Return(nil, errors.New("authentication error"))
mockRepository := repository.NewMockInterface(t)
mockCloser := io_mock.NewMockCloser(t)
mockCloser.EXPECT().
Close().
Return(nil)
mockRepository := repository_mock.NewMockInterface(t)
mockRepository.EXPECT().
Lock("/path/to/token-cache", tokenCacheKey).
Return(mockCloser, nil)
mockRepository.EXPECT().
FindByKey("/path/to/token-cache", tokencache.Key{
IssuerURL: "https://accounts.google.com",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
Provider: oidc.Provider{
IssuerURL: "https://accounts.google.com",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
},
}).
Return(nil, errors.New("file not found"))
mockReader := reader_mock.NewMockInterface(t)
mockReader.EXPECT().
Read().
Return(credentialpluginInput, nil)
u := GetToken{
Authentication: mockAuthentication,
TokenCacheRepository: mockRepository,
Writer: writer.NewMockInterface(t),
Mutex: mutex.NewMockInterface(t),
Logger: logger.New(t),
Authentication: mockAuthentication,
TokenCacheRepository: mockRepository,
CredentialPluginReader: mockReader,
CredentialPluginWriter: writer_mock.NewMockInterface(t),
Logger: logger.New(t),
Clock: clock.Fake(expiryTime.Add(-time.Hour)),
}
if err := u.Do(ctx, in); err == nil {
t.Errorf("err wants non-nil but nil")

View File

@@ -74,6 +74,7 @@ type Stage2Input struct {
ClientSecret string
ExtraScopes []string // optional
UsePKCE bool // optional
UseAccessToken bool // optional
ListenAddressArgs []string // non-nil if set by the command arg
GrantOptionSet authentication.GrantOptionSet
TLSClientConfig tlsclientconfig.Config
@@ -91,6 +92,7 @@ func (u *Setup) DoStage2(ctx context.Context, in Stage2Input) error {
},
GrantOptionSet: in.GrantOptionSet,
TLSClientConfig: in.TLSClientConfig,
UseAccessToken: in.UseAccessToken,
})
if err != nil {
return fmt.Errorf("authentication error: %w", err)
@@ -128,6 +130,9 @@ func makeCredentialPluginArgs(in Stage2Input) []string {
if in.UsePKCE {
args = append(args, "--oidc-use-pkce")
}
if in.UseAccessToken {
args = append(args, "--oidc-use-access-token")
}
for _, f := range in.TLSClientConfig.CACertFilename {
args = append(args, "--certificate-authority="+f)
}

View File

@@ -6,6 +6,7 @@ import (
"time"
"github.com/golang-jwt/jwt/v5"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/usecases/authentication_mock"
"github.com/int128/kubelogin/pkg/oidc"
testingJWT "github.com/int128/kubelogin/pkg/testing/jwt"
"github.com/int128/kubelogin/pkg/testing/logger"
@@ -36,7 +37,7 @@ func TestSetup_DoStage2(t *testing.T) {
GrantOptionSet: grantOptionSet,
TLSClientConfig: dummyTLSClientConfig,
}
mockAuthentication := authentication.NewMockInterface(t)
mockAuthentication := authentication_mock.NewMockInterface(t)
mockAuthentication.EXPECT().
Do(ctx, authentication.Input{
Provider: oidc.Provider{

View File

@@ -5,6 +5,7 @@ import (
"fmt"
"github.com/google/wire"
"github.com/int128/kubelogin/pkg/infrastructure/clock"
"github.com/int128/kubelogin/pkg/infrastructure/logger"
"github.com/int128/kubelogin/pkg/kubeconfig"
"github.com/int128/kubelogin/pkg/kubeconfig/loader"
@@ -52,6 +53,7 @@ type Standalone struct {
KubeconfigLoader loader.Interface
KubeconfigWriter writer.Interface
Logger logger.Interface
Clock clock.Interface
}
func (u *Standalone) Do(ctx context.Context, in Input) error {
@@ -78,6 +80,18 @@ func (u *Standalone) Do(ctx context.Context, in Input) error {
IDToken: authProvider.IDToken,
RefreshToken: authProvider.RefreshToken,
}
u.Logger.V(1).Infof("checking expiration of the existing token")
// Skip verification of the token to reduce time of a discovery request.
// Here it trusts the signature and claims and checks only expiration,
// because the token has been verified before caching.
claims, err := cachedTokenSet.DecodeWithoutVerify()
if err != nil {
return fmt.Errorf("invalid token cache (you may need to remove): %w", err)
}
if !claims.IsExpired(u.Clock) {
u.Logger.V(1).Infof("you already have a valid token until %s", claims.Expiry)
return nil
}
}
authenticationInput := authentication.Input{
@@ -101,11 +115,6 @@ func (u *Standalone) Do(ctx context.Context, in Input) error {
return fmt.Errorf("you got an invalid token: %w", err)
}
u.Logger.V(1).Infof("you got a token: %s", idTokenClaims.Pretty)
if authenticationOutput.AlreadyHasValidIDToken {
u.Logger.Printf("You already have a valid token until %s", idTokenClaims.Expiry)
return nil
}
u.Logger.Printf("You got a valid token until %s", idTokenClaims.Expiry)
authProvider.IDToken = authenticationOutput.TokenSet.IDToken
authProvider.RefreshToken = authenticationOutput.TokenSet.RefreshToken

View File

@@ -7,10 +7,12 @@ import (
"time"
"github.com/golang-jwt/jwt/v5"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/kubeconfig/loader_mock"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/kubeconfig/writer_mock"
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/usecases/authentication_mock"
"github.com/int128/kubelogin/pkg/kubeconfig"
"github.com/int128/kubelogin/pkg/kubeconfig/loader"
"github.com/int128/kubelogin/pkg/kubeconfig/writer"
"github.com/int128/kubelogin/pkg/oidc"
"github.com/int128/kubelogin/pkg/testing/clock"
testingJWT "github.com/int128/kubelogin/pkg/testing/jwt"
"github.com/int128/kubelogin/pkg/testing/logger"
"github.com/int128/kubelogin/pkg/tlsclientconfig"
@@ -18,11 +20,11 @@ import (
)
func TestStandalone_Do(t *testing.T) {
issuedIDTokenExpiration := time.Now().Add(1 * time.Hour).Round(time.Second)
expiryTime := time.Date(2020, 1, 2, 3, 4, 5, 0, time.UTC)
issuedIDToken := testingJWT.EncodeF(t, func(claims *testingJWT.Claims) {
claims.Issuer = "https://accounts.google.com"
claims.Subject = "YOUR_SUBJECT"
claims.ExpiresAt = jwt.NewNumericDate(issuedIDTokenExpiration)
claims.ExpiresAt = jwt.NewNumericDate(expiryTime)
})
t.Run("FullOptions", func(t *testing.T) {
@@ -43,11 +45,11 @@ func TestStandalone_Do(t *testing.T) {
IDPCertificateAuthority: "/path/to/cert2",
IDPCertificateAuthorityData: "BASE64ENCODED2",
}
mockLoader := loader.NewMockInterface(t)
mockLoader := loader_mock.NewMockInterface(t)
mockLoader.EXPECT().
GetCurrentAuthProvider("/path/to/kubeconfig", kubeconfig.ContextName("theContext"), kubeconfig.UserName("theUser")).
Return(currentAuthProvider, nil)
mockWriter := writer.NewMockInterface(t)
mockWriter := writer_mock.NewMockInterface(t)
mockWriter.EXPECT().
UpdateAuthProvider(kubeconfig.AuthProvider{
LocationOfOrigin: "/path/to/kubeconfig",
@@ -61,7 +63,7 @@ func TestStandalone_Do(t *testing.T) {
RefreshToken: "YOUR_REFRESH_TOKEN",
}).
Return(nil)
mockAuthentication := authentication.NewMockInterface(t)
mockAuthentication := authentication_mock.NewMockInterface(t)
mockAuthentication.EXPECT().
Do(ctx, authentication.Input{
Provider: oidc.Provider{
@@ -86,6 +88,7 @@ func TestStandalone_Do(t *testing.T) {
KubeconfigLoader: mockLoader,
KubeconfigWriter: mockWriter,
Logger: logger.New(t),
Clock: clock.Fake(expiryTime.Add(-time.Hour)),
}
if err := u.Do(ctx, in); err != nil {
t.Errorf("Do returned error: %+v", err)
@@ -103,32 +106,15 @@ func TestStandalone_Do(t *testing.T) {
ClientSecret: "YOUR_CLIENT_SECRET",
IDToken: issuedIDToken,
}
mockLoader := loader.NewMockInterface(t)
mockLoader := loader_mock.NewMockInterface(t)
mockLoader.EXPECT().
GetCurrentAuthProvider("", kubeconfig.ContextName(""), kubeconfig.UserName("")).
Return(currentAuthProvider, nil)
mockAuthentication := authentication.NewMockInterface(t)
mockAuthentication.EXPECT().
Do(ctx, authentication.Input{
Provider: oidc.Provider{
IssuerURL: "https://accounts.google.com",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
},
CachedTokenSet: &oidc.TokenSet{
IDToken: issuedIDToken,
},
}).
Return(&authentication.Output{
AlreadyHasValidIDToken: true,
TokenSet: oidc.TokenSet{
IDToken: issuedIDToken,
},
}, nil)
u := Standalone{
Authentication: mockAuthentication,
Authentication: authentication_mock.NewMockInterface(t),
KubeconfigLoader: mockLoader,
Logger: logger.New(t),
Clock: clock.Fake(expiryTime.Add(-time.Hour)),
}
if err := u.Do(ctx, in); err != nil {
t.Errorf("Do returned error: %+v", err)
@@ -138,15 +124,16 @@ func TestStandalone_Do(t *testing.T) {
t.Run("NoOIDCConfig", func(t *testing.T) {
ctx := context.TODO()
in := Input{}
mockLoader := loader.NewMockInterface(t)
mockLoader := loader_mock.NewMockInterface(t)
mockLoader.EXPECT().
GetCurrentAuthProvider("", kubeconfig.ContextName(""), kubeconfig.UserName("")).
Return(nil, errors.New("no oidc config"))
mockAuthentication := authentication.NewMockInterface(t)
mockAuthentication := authentication_mock.NewMockInterface(t)
u := Standalone{
Authentication: mockAuthentication,
KubeconfigLoader: mockLoader,
Logger: logger.New(t),
Clock: clock.Fake(expiryTime.Add(-time.Hour)),
}
if err := u.Do(ctx, in); err == nil {
t.Errorf("err wants non-nil but nil")
@@ -163,11 +150,11 @@ func TestStandalone_Do(t *testing.T) {
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
}
mockLoader := loader.NewMockInterface(t)
mockLoader := loader_mock.NewMockInterface(t)
mockLoader.EXPECT().
GetCurrentAuthProvider("", kubeconfig.ContextName(""), kubeconfig.UserName("")).
Return(currentAuthProvider, nil)
mockAuthentication := authentication.NewMockInterface(t)
mockAuthentication := authentication_mock.NewMockInterface(t)
mockAuthentication.EXPECT().
Do(ctx, authentication.Input{
Provider: oidc.Provider{
@@ -181,6 +168,7 @@ func TestStandalone_Do(t *testing.T) {
Authentication: mockAuthentication,
KubeconfigLoader: mockLoader,
Logger: logger.New(t),
Clock: clock.Fake(expiryTime.Add(-time.Hour)),
}
if err := u.Do(ctx, in); err == nil {
t.Errorf("err wants non-nil but nil")
@@ -197,11 +185,11 @@ func TestStandalone_Do(t *testing.T) {
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
}
mockLoader := loader.NewMockInterface(t)
mockLoader := loader_mock.NewMockInterface(t)
mockLoader.EXPECT().
GetCurrentAuthProvider("", kubeconfig.ContextName(""), kubeconfig.UserName("")).
Return(currentAuthProvider, nil)
mockWriter := writer.NewMockInterface(t)
mockWriter := writer_mock.NewMockInterface(t)
mockWriter.EXPECT().
UpdateAuthProvider(kubeconfig.AuthProvider{
LocationOfOrigin: "/path/to/kubeconfig",
@@ -213,7 +201,7 @@ func TestStandalone_Do(t *testing.T) {
RefreshToken: "YOUR_REFRESH_TOKEN",
}).
Return(errors.New("I/O error"))
mockAuthentication := authentication.NewMockInterface(t)
mockAuthentication := authentication_mock.NewMockInterface(t)
mockAuthentication.EXPECT().
Do(ctx, authentication.Input{
Provider: oidc.Provider{
@@ -233,6 +221,7 @@ func TestStandalone_Do(t *testing.T) {
KubeconfigLoader: mockLoader,
KubeconfigWriter: mockWriter,
Logger: logger.New(t),
Clock: clock.Fake(expiryTime.Add(-time.Hour)),
}
if err := u.Do(ctx, in); err == nil {
t.Errorf("err wants non-nil but nil")

View File

@@ -5,7 +5,7 @@ dex: dex.yaml
# wait for kind network
while true; do if docker network inspect kind; then break; fi; sleep 1; done
# create a container
docker create --name dex-server -p 10443:10443 --network kind quay.io/dexidp/dex:v2.21.0 serve /dex.yaml
docker create -q --name dex-server -p 10443:10443 --network kind ghcr.io/dexidp/dex:v2.39.0 dex serve /dex.yaml
# deploy the config
docker cp $(CERT_DIR)/server.crt dex-server:/
docker cp $(CERT_DIR)/server.key dex-server:/

View File

@@ -19,7 +19,8 @@ test: build
--browser-command=$(BIN_DIR)/chromelogin
# set up the kubeconfig
kubectl config set-credentials oidc \
--exec-api-version=client.authentication.k8s.io/v1beta1 \
--exec-api-version=client.authentication.k8s.io/v1 \
--exec-interactive-mode=Never \
--exec-command=kubectl \
--exec-arg=oidc-login \
--exec-arg=get-token \

View File

@@ -28,20 +28,29 @@ func main() {
func runBrowser(ctx context.Context, url string) error {
execOpts := chromedp.DefaultExecAllocatorOptions[:]
execOpts = append(execOpts, chromedp.NoSandbox)
ctx, cancel := chromedp.NewExecAllocator(ctx, execOpts...)
defer cancel()
ctx, cancel = chromedp.NewContext(ctx, chromedp.WithLogf(log.Printf))
defer cancel()
ctx, cancel = context.WithTimeout(ctx, 30*time.Second)
defer cancel()
if err := logInToDex(ctx, url); err != nil {
execOpts = append(execOpts,
chromedp.NoSandbox,
chromedp.WSURLReadTimeout(30*time.Second),
)
ctx, cancelExec := chromedp.NewExecAllocator(ctx, execOpts...)
defer cancelExec()
ctx, cancelCtx := chromedp.NewContext(ctx, chromedp.WithLogf(log.Printf))
defer cancelCtx()
log.Printf("Opening a new browser and navigating to %s", url)
if err := openBrowser(ctx, url); err != nil {
return fmt.Errorf("could not open a new browser: %w", err)
}
ctx, cancelTimeout := context.WithTimeout(ctx, 30*time.Second)
defer cancelTimeout()
log.Printf("Logging in to Dex")
if err := logInToDex(ctx); err != nil {
return fmt.Errorf("could not run the browser: %w", err)
}
return nil
}
func logInToDex(ctx context.Context, url string) error {
func openBrowser(ctx context.Context, url string) error {
for {
var location string
err := chromedp.Run(ctx,
@@ -51,14 +60,16 @@ func logInToDex(ctx context.Context, url string) error {
if err != nil {
return err
}
log.Printf("location: %s", location)
log.Printf("Location: %s", location)
if strings.HasPrefix(location, `http://`) || strings.HasPrefix(location, `https://`) {
break
return nil
}
time.Sleep(1 * time.Second)
}
}
err := chromedp.Run(ctx,
func logInToDex(ctx context.Context) error {
return chromedp.Run(ctx,
// https://dex-server:10443/dex/auth/local
chromedp.WaitVisible(`#login`),
logPageMetadata(),
@@ -73,10 +84,6 @@ func logInToDex(ctx context.Context, url string) error {
chromedp.WaitReady(`body`),
logPageMetadata(),
)
if err != nil {
return err
}
return nil
}
func logPageMetadata() chromedp.Action {
@@ -86,7 +93,7 @@ func logPageMetadata() chromedp.Action {
chromedp.Location(&location),
chromedp.Title(&title),
chromedp.ActionFunc(func(ctx context.Context) error {
log.Printf("location: %s [%s]", location, title)
log.Printf("Location: %s, Title: %s", location, title)
return nil
}),
}

13
tools/Makefile Normal file
View File

@@ -0,0 +1,13 @@
GOBIN := $(CURDIR)/bin
export GOBIN
all: bin/mockery bin/wire bin/golangci-lint
bin/mockery:
go install github.com/vektra/mockery/v2
bin/wire:
go install github.com/google/wire/cmd/wire
bin/golangci-lint:
go install github.com/golangci/golangci-lint/cmd/golangci-lint

205
tools/go.mod Normal file
View File

@@ -0,0 +1,205 @@
module github.com/int128/kubelogin/tools
go 1.23.4
require (
github.com/golangci/golangci-lint v1.63.4
github.com/google/wire v0.6.0
github.com/vektra/mockery/v2 v2.50.4
)
require (
4d63.com/gocheckcompilerdirectives v1.2.1 // indirect
4d63.com/gochecknoglobals v0.2.1 // indirect
github.com/4meepo/tagalign v1.4.1 // indirect
github.com/Abirdcfly/dupword v0.1.3 // indirect
github.com/Antonboom/errname v1.0.0 // indirect
github.com/Antonboom/nilnil v1.0.1 // indirect
github.com/Antonboom/testifylint v1.5.2 // indirect
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect
github.com/Crocmagnon/fatcontext v0.5.3 // indirect
github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24 // indirect
github.com/GaijinEntertainment/go-exhaustruct/v3 v3.3.0 // indirect
github.com/Masterminds/semver/v3 v3.3.0 // indirect
github.com/OpenPeeDeeP/depguard/v2 v2.2.0 // indirect
github.com/alecthomas/go-check-sumtype v0.3.1 // indirect
github.com/alexkohler/nakedret/v2 v2.0.5 // indirect
github.com/alexkohler/prealloc v1.0.0 // indirect
github.com/alingse/asasalint v0.0.11 // indirect
github.com/alingse/nilnesserr v0.1.1 // indirect
github.com/ashanbrown/forbidigo v1.6.0 // indirect
github.com/ashanbrown/makezero v1.2.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bkielbasa/cyclop v1.2.3 // indirect
github.com/blizzy78/varnamelen v0.8.0 // indirect
github.com/bombsimon/wsl/v4 v4.5.0 // indirect
github.com/breml/bidichk v0.3.2 // indirect
github.com/breml/errchkjson v0.4.0 // indirect
github.com/butuzov/ireturn v0.3.1 // indirect
github.com/butuzov/mirror v1.3.0 // indirect
github.com/catenacyber/perfsprint v0.7.1 // indirect
github.com/ccojocar/zxcvbn-go v1.0.2 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/charithe/durationcheck v0.0.10 // indirect
github.com/chavacava/garif v0.1.0 // indirect
github.com/chigopher/pathlib v0.19.1 // indirect
github.com/ckaznocha/intrange v0.3.0 // indirect
github.com/curioswitch/go-reassign v0.3.0 // indirect
github.com/daixiang0/gci v0.13.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/denis-tingaikin/go-header v0.5.0 // indirect
github.com/ettle/strcase v0.2.0 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/fatih/structtag v1.2.0 // indirect
github.com/firefart/nonamedreturns v1.0.5 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/fzipp/gocyclo v0.6.0 // indirect
github.com/ghostiam/protogetter v0.3.8 // indirect
github.com/go-critic/go-critic v0.11.5 // indirect
github.com/go-toolsmith/astcast v1.1.0 // indirect
github.com/go-toolsmith/astcopy v1.1.0 // indirect
github.com/go-toolsmith/astequal v1.2.0 // indirect
github.com/go-toolsmith/astfmt v1.1.0 // indirect
github.com/go-toolsmith/astp v1.1.0 // indirect
github.com/go-toolsmith/strparse v1.1.0 // indirect
github.com/go-toolsmith/typep v1.1.0 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/gofrs/flock v0.12.1 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect
github.com/golangci/go-printf-func-name v0.1.0 // indirect
github.com/golangci/gofmt v0.0.0-20241223200906-057b0627d9b9 // indirect
github.com/golangci/misspell v0.6.0 // indirect
github.com/golangci/plugin-module-register v0.1.1 // indirect
github.com/golangci/revgrep v0.5.3 // indirect
github.com/golangci/unconvert v0.0.0-20240309020433-c5143eacb3ed // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/subcommands v1.2.0 // indirect
github.com/gordonklaus/ineffassign v0.1.0 // indirect
github.com/gostaticanalysis/analysisutil v0.7.1 // indirect
github.com/gostaticanalysis/comment v1.4.2 // indirect
github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect
github.com/gostaticanalysis/nilerr v0.1.1 // indirect
github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/iancoleman/strcase v0.2.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/jgautheron/goconst v1.7.1 // indirect
github.com/jingyugao/rowserrcheck v1.1.1 // indirect
github.com/jinzhu/copier v0.3.5 // indirect
github.com/jjti/go-spancheck v0.6.4 // indirect
github.com/julz/importas v0.2.0 // indirect
github.com/karamaru-alpha/copyloopvar v1.1.0 // indirect
github.com/kisielk/errcheck v1.8.0 // indirect
github.com/kkHAIKE/contextcheck v1.1.5 // indirect
github.com/kulti/thelper v0.6.3 // indirect
github.com/kunwardeep/paralleltest v1.0.10 // indirect
github.com/kyoh86/exportloopref v0.1.11 // indirect
github.com/lasiar/canonicalheader v1.1.2 // indirect
github.com/ldez/exptostd v0.3.1 // indirect
github.com/ldez/gomoddirectives v0.6.0 // indirect
github.com/ldez/grignotin v0.7.0 // indirect
github.com/ldez/tagliatelle v0.7.1 // indirect
github.com/ldez/usetesting v0.4.2 // indirect
github.com/leonklingele/grouper v1.1.2 // indirect
github.com/macabu/inamedparam v0.1.3 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/maratori/testableexamples v1.0.0 // indirect
github.com/maratori/testpackage v1.1.1 // indirect
github.com/matoous/godox v0.0.0-20230222163458-006bad1f9d26 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mgechev/revive v1.5.1 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/moricho/tparallel v0.3.2 // indirect
github.com/nakabonne/nestif v0.3.1 // indirect
github.com/nishanths/exhaustive v0.12.0 // indirect
github.com/nishanths/predeclared v0.2.2 // indirect
github.com/nunnatsa/ginkgolinter v0.18.4 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/polyfloyd/go-errorlint v1.7.0 // indirect
github.com/prometheus/client_golang v1.12.1 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/quasilyte/go-ruleguard v0.4.3-0.20240823090925-0fe6f58b47b1 // indirect
github.com/quasilyte/go-ruleguard/dsl v0.3.22 // indirect
github.com/quasilyte/gogrep v0.5.0 // indirect
github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect
github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect
github.com/raeperd/recvcheck v0.2.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/rs/zerolog v1.29.0 // indirect
github.com/ryancurrah/gomodguard v1.3.5 // indirect
github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect
github.com/sanposhiho/wastedassign/v2 v2.1.0 // indirect
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 // indirect
github.com/sashamelentyev/interfacebloat v1.1.0 // indirect
github.com/sashamelentyev/usestdlibvars v1.28.0 // indirect
github.com/securego/gosec/v2 v2.21.4 // indirect
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/sivchari/containedctx v1.0.3 // indirect
github.com/sivchari/tenv v1.12.1 // indirect
github.com/sonatard/noctx v0.1.0 // indirect
github.com/sourcegraph/go-diff v0.7.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/cobra v1.8.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.15.0 // indirect
github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect
github.com/stbenjam/no-sprintf-host-port v0.2.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/stretchr/testify v1.10.0 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
github.com/tdakkota/asciicheck v0.3.0 // indirect
github.com/tetafro/godot v1.4.20 // indirect
github.com/timakin/bodyclose v0.0.0-20241017074812-ed6a65f985e3 // indirect
github.com/timonwong/loggercheck v0.10.1 // indirect
github.com/tomarrell/wrapcheck/v2 v2.10.0 // indirect
github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect
github.com/ultraware/funlen v0.2.0 // indirect
github.com/ultraware/whitespace v0.2.0 // indirect
github.com/uudashr/gocognit v1.2.0 // indirect
github.com/uudashr/iface v1.3.0 // indirect
github.com/xen0n/gosmopolitan v1.2.2 // indirect
github.com/yagipy/maintidx v1.0.0 // indirect
github.com/yeya24/promlinter v0.3.0 // indirect
github.com/ykadowak/zerologlint v0.1.5 // indirect
gitlab.com/bosi/decorder v0.4.2 // indirect
go-simpler.org/musttag v0.13.0 // indirect
go-simpler.org/sloglint v0.7.2 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/automaxprocs v1.6.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.24.0 // indirect
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
golang.org/x/exp/typeparams v0.0.0-20241108190413-2d47ceb2692f // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/term v0.16.0 // indirect
golang.org/x/text v0.20.0 // indirect
golang.org/x/tools v0.28.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
honnef.co/go/tools v0.5.1 // indirect
mvdan.cc/gofumpt v0.7.0 // indirect
mvdan.cc/unparam v0.0.0-20240528143540-8a5130ca722f // indirect
)

1017
tools/go.sum Normal file

File diff suppressed because it is too large Load Diff

9
tools/tools.go Normal file
View File

@@ -0,0 +1,9 @@
//go:build tools
package main
import (
_ "github.com/google/wire/cmd/wire"
_ "github.com/vektra/mockery/v2/cmd"
_ "github.com/golangci/golangci-lint/cmd/golangci-lint"
)