Compare commits

...

760 Commits

Author SHA1 Message Date
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
renovate[bot]
852a040607 chore(deps): update dependency golangci/golangci-lint to v1.59.0 (#1094)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-26 21:17:06 +00:00
renovate[bot]
173192da4d chore(deps): update dependency golangci/golangci-lint to v1.58.2 (#1093)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-19 23:29:53 +00:00
renovate[bot]
72912ff126 fix(deps): update kubernetes packages to v0.30.1 (#1092)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-16 05:37:16 +00:00
renovate[bot]
94ca6bc8d2 chore(deps): update dependency golang-version to v1.22.3 (#1090)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-09 03:24:29 +00:00
renovate[bot]
ad39239e7f chore(deps): update dependency golangci/golangci-lint to v1.58.1 (#1091)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-09 02:07:09 +00:00
renovate[bot]
88a134e5b1 fix(deps): update module golang.org/x/net to v0.25.0 (#1089)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-06 22:23:03 +00:00
renovate[bot]
95bfdedf3f fix(deps): update module golang.org/x/term to v0.20.0 (#1087)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-05 19:49:40 +00:00
renovate[bot]
48cd10d595 fix(deps): update module golang.org/x/oauth2 to v0.20.0 (#1086)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-04 18:45:52 +00:00
renovate[bot]
ae54330f2c chore(deps): update dependency golangci/golangci-lint to v1.58.0 (#1085)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-04 00:03:15 +00:00
renovate[bot]
fdcdcc3a60 chore(deps): update dependency go to v1.22.2 (#1080)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-18 08:41:07 +00:00
renovate[bot]
3d9ce981ce fix(deps): update kubernetes packages to v0.30.0 (#1079)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-18 05:06:40 +00:00
renovate[bot]
5185211e70 fix(deps): update kubernetes packages to v0.29.4 (#1078)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-17 06:33:38 +00:00
renovate[bot]
e4caacf78c fix(deps): update module golang.org/x/sync to v0.7.0 (#1075)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-04 21:53:00 +00:00
renovate[bot]
15482ee981 fix(deps): update module golang.org/x/net to v0.24.0 (#1076)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-04 19:53:26 +00:00
renovate[bot]
596791e365 fix(deps): update module golang.org/x/oauth2 to v0.19.0 (#1074)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-04 19:52:54 +00:00
renovate[bot]
c088abbf7e fix(deps): update module golang.org/x/net to v0.23.0 (#1072)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-03 22:56:36 +00:00
renovate[bot]
1c38f8cd1d chore(deps): update dependency golang-version to v1.22.2 (#1071)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-03 20:03:24 +00:00
renovate[bot]
885adc8562 chore(deps): update dependency golangci/golangci-lint to v1.57.2 (#1070)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-29 01:30:13 +00:00
renovate[bot]
a4714fe2f8 chore(deps): update dependency golangci/golangci-lint to v1.57.1 (#1068)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-20 23:50:12 +00:00
renovate[bot]
8f9e7a7f0f chore(deps): update dependency golangci/golangci-lint to v1.57.0 (#1067)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-20 03:35:20 +00:00
renovate[bot]
7ddb6d0277 fix(deps): update module github.com/coreos/go-oidc/v3 to v3.10.0 (#1066)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-19 21:55:17 +00:00
renovate[bot]
c52239678e fix(deps): update kubernetes packages to v0.29.3 (#1065)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-16 03:04:03 +00:00
renovate[bot]
c23d373d80 chore(deps): update dependency golang-version to v1.22.1 (#1061)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-05 21:01:34 +00:00
renovate[bot]
ce15cb284c fix(deps): update module golang.org/x/oauth2 to v0.18.0 (#1059)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-05 09:32:23 +00:00
renovate[bot]
526bd85947 fix(deps): update module github.com/golang-jwt/jwt/v5 to v5.2.1 (#1060)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-05 07:00:18 +00:00
renovate[bot]
ba5f2e36e7 fix(deps): update module golang.org/x/net to v0.22.0 (#1058)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-05 01:09:47 +00:00
renovate[bot]
eee5cd92db fix(deps): update module golang.org/x/term to v0.18.0 (#1057)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-04 22:18:07 +00:00
renovate[bot]
1dbfff621f fix(deps): update module github.com/stretchr/testify to v1.9.0 (#1056)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-02 22:37:38 +00:00
renovate[bot]
53718139f2 chore(deps): update dependency golangci/golangci-lint to v1.56.2 (#1051)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-15 22:13:02 +00:00
renovate[bot]
e8e7f6b4d4 fix(deps): update kubernetes packages to v0.29.2 (#1050)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-15 03:50:40 +00:00
renovate[bot]
7832d45c27 chore(deps): update dependency golangci/golangci-lint to v1.56.1 (#1047)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-08 22:00:56 +00:00
renovate[bot]
6e166357c3 fix(deps): update module golang.org/x/oauth2 to v0.17.0 (#1046)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-08 18:21:06 +00:00
renovate[bot]
35bb3a6297 fix(deps): update module golang.org/x/net to v0.21.0 (#1045)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-08 04:03:02 +00:00
renovate[bot]
45bad277b6 fix(deps): update module github.com/google/wire to v0.6.0 (#1043)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-08 00:28:17 +00:00
renovate[bot]
9878c2a7e9 chore(deps): update golang docker tag to v1.22 (#1041)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-07 22:37:43 +00:00
renovate[bot]
d34faa478c chore(deps): update dependency golangci/golangci-lint to v1.56.0 (#1042)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-07 18:10:07 +00:00
renovate[bot]
a6f22d9acc fix(deps): update module github.com/chromedp/chromedp to v0.9.5 (#1038)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-07 06:53:25 +00:00
renovate[bot]
d1a6bea6a9 chore(deps): update dependency golang-version to v1.22.0 (#1040)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-07 03:08:32 +00:00
renovate[bot]
c68df0f232 fix(deps): update module github.com/chromedp/chromedp to v0.9.4 (#1036)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-02 01:36:43 +00:00
renovate[bot]
cf6ebe8da2 fix(deps): update module k8s.io/klog/v2 to v2.120.1 (#1035)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-18 20:26:34 +00:00
renovate[bot]
2cb45ad66a fix(deps): update kubernetes packages to v0.29.1 (#1034)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-18 03:51:52 +00:00
renovate[bot]
72062a6ff1 chore(deps): update int128/go-workflows action to v0.3.0 (#1033)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-15 10:15:04 +00:00
renovate[bot]
79a6f85967 fix(deps): update module github.com/alexflint/go-filemutex to v1.3.0 (#1032)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-11 20:10:41 +00:00
renovate[bot]
7f651e7b3d fix(deps): update module k8s.io/klog/v2 to v2.120.0 (#1031)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-10 22:48:35 +00:00
renovate[bot]
4519d1b320 chore(deps): update dependency golang-version to v1.21.6 (#1029)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-10 00:36:10 +00:00
renovate[bot]
1ae6b219c7 fix(deps): update module golang.org/x/oauth2 to v0.16.0 (#1027)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-09 00:15:57 +00:00
renovate[bot]
44d388a9e1 fix(deps): update module golang.org/x/net to v0.20.0 (#1026)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-08 23:26:03 +00:00
renovate[bot]
87c8086fc7 fix(deps): update module golang.org/x/term to v0.16.0 (#1025)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-04 22:13:37 +00:00
renovate[bot]
18c8f85530 fix(deps): update module golang.org/x/sync to v0.6.0 (#1024)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-04 19:13:49 +00:00
renovate[bot]
8a17c34be1 fix(deps): update github.com/pkg/browser digest to 5ac0b6a (#1023)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-02 14:21:14 +00:00
Hidetake Iwata
967cdaac59 Parallel build of multi-architectures image (#1021)
* Parallel build of multi-architectures image

* Test image
2023-12-17 14:53:41 +09:00
renovate[bot]
e0155675b1 chore(deps): update int128/go-workflows action to v0.2.1 (#1022)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-17 05:46:26 +00:00
Hidetake Iwata
e0ee661cab Bump int128/go-release-action@v2 (#1020) 2023-12-17 13:45:56 +09:00
Hidetake Iwata
7b22915e28 Build multi-architectures image in single job (#1019) 2023-12-17 10:25:46 +09:00
github-actions[bot]
5dd50923c2 Generated by GitHub Actions (go / fmt) (#1018)
https://github.com/int128/kubelogin/actions/runs/7229804014

Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
2023-12-16 13:35:36 +09:00
Tobias Wolter
9da00c5e21 Respect KUBECACHEDIR environment variable (#975)
This adds a check for the existence of a (non-empty) `KUBECACHEDIR`
environment variable that will be used to construct the cache directory
path if present.
2023-12-16 13:32:42 +09:00
Mike Williams
e41b425ef4 fix(docker): Bump to distroless debian12 for golang:1.21 binaries (#980)
golang:1.21 binaries are compiled to require at least GLIBC 2.36, debian 10 is only 2.31.
2023-12-16 13:24:27 +09:00
renovate[bot]
0aae8ad815 fix(deps): update kubernetes packages to v0.29.0 (#1017)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-14 19:46:46 +00:00
renovate[bot]
da85dfa303 fix(deps): update module github.com/coreos/go-oidc/v3 to v3.9.0 (#1016)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-09 21:11:00 +00:00
renovate[bot]
788b3258a1 chore(deps): update actions/setup-go action to v5 (#1015) 2023-12-09 21:12:06 +09:00
renovate[bot]
c5847ea24f chore(deps): update dependency golang-version to v1.21.5 (#1014)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-05 22:12:15 +00:00
renovate[bot]
2cf9fcd390 fix(deps): update module github.com/golang-jwt/jwt/v5 to v5.2.0 (#1013)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-02 05:26:38 +00:00
renovate[bot]
ca5cf85b29 fix(deps): update module github.com/coreos/go-oidc/v3 to v3.8.0 (#1012)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-28 12:28:53 +00:00
renovate[bot]
a24c5752f3 fix(deps): update module golang.org/x/oauth2 to v0.15.0 (#1011)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-28 00:58:01 +00:00
renovate[bot]
36b9709c05 fix(deps): update module golang.org/x/net to v0.19.0 (#1010)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-27 22:48:59 +00:00
renovate[bot]
4503cfacb9 fix(deps): update module golang.org/x/term to v0.15.0 (#1009)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-27 19:51:53 +00:00
renovate[bot]
94f4145193 fix(deps): update kubernetes packages to v0.28.4 (#1008)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-16 06:14:40 +00:00
renovate[bot]
b1575d2878 fix(deps): update module golang.org/x/oauth2 to v0.14.0 (#1007)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-09 04:02:25 +00:00
renovate[bot]
649e394358 fix(deps): update module golang.org/x/net to v0.18.0 (#1006)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-09 01:45:18 +00:00
renovate[bot]
78c44eb0cc fix(deps): update module golang.org/x/term to v0.14.0 (#1005)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-08 09:45:16 +00:00
renovate[bot]
e60821fb70 fix(deps): update module github.com/golang-jwt/jwt/v5 to v5.1.0 (#1004)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-08 07:48:41 +00:00
renovate[bot]
5b0e22e090 chore(deps): update dependency golang-version to v1.21.4 (#1003)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-07 23:57:39 +00:00
renovate[bot]
2daa1dac45 fix(deps): update module github.com/spf13/cobra to v1.8.0 (#1002)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-05 00:33:12 +00:00
renovate[bot]
6d43cf81d9 fix(deps): update module golang.org/x/sync to v0.5.0 (#1001)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-04 19:21:41 +00:00
renovate[bot]
b7a98f41d0 chore(deps): update dependency golangci/golangci-lint to v1.55.2 (#1000)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-03 18:28:46 +00:00
renovate[bot]
6370cab657 fix(deps): update module k8s.io/klog/v2 to v2.110.1 (#999)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-31 16:14:26 +00:00
renovate[bot]
bb41bb5726 chore(deps): update int128/go-workflows action to v0.2.0 (#998)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-28 03:45:48 +00:00
renovate[bot]
8d3cb4682e chore(deps): update dependency golangci/golangci-lint to v1.55.1 (#997)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-25 15:34:45 +00:00
renovate[bot]
8005dfe948 chore(deps): update dependency golangci/golangci-lint to v1.55.0 (#996)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-20 17:13:14 +00:00
renovate[bot]
0a749a7d07 fix(deps): update module github.com/coreos/go-oidc/v3 to v3.7.0 (#995)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-20 09:28:50 +00:00
renovate[bot]
518ce6da18 fix(deps): update kubernetes packages to v0.28.3 (#994)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-18 18:32:10 +00:00
renovate[bot]
4ec4812b35 fix(deps): update module github.com/chromedp/chromedp to v0.9.3 (#993)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-11 09:52:49 +00:00
renovate[bot]
b7004d4312 fix(deps): update module golang.org/x/net to v0.17.0 (#992)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-11 04:50:47 +00:00
renovate[bot]
2f432bf3ea fix(deps): update module github.com/google/go-cmp to v0.6.0 (#991)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-11 01:47:44 +00:00
renovate[bot]
ac0725ae46 chore(deps): update dependency golang-version to v1.21.3 (#990)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-10 21:21:34 +00:00
renovate[bot]
20a024b3c4 fix(deps): update module golang.org/x/oauth2 to v0.13.0 (#988)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-06 13:48:26 +00:00
renovate[bot]
7a36e88579 fix(deps): update module golang.org/x/net to v0.16.0 (#987)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-06 03:58:28 +00:00
renovate[bot]
a514ed807c chore(deps): update dependency golang-version to v1.21.2 (#986)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-06 00:23:37 +00:00
renovate[bot]
9c3fe1c247 fix(deps): update module golang.org/x/term to v0.13.0 (#985)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-05 18:59:24 +00:00
renovate[bot]
e7a2ea0da1 fix(deps): update module golang.org/x/sync to v0.4.0 (#984)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-05 16:09:04 +00:00
renovate[bot]
e35ee4ca61 fix(deps): update kubernetes packages to v0.28.2 (#983)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-14 00:47:03 +00:00
renovate[bot]
fc630b21f6 chore(deps): update actions/checkout action to v4 (#977)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-10 13:22:38 +00:00
renovate[bot]
6d6e084ebe fix(deps): update module github.com/int128/oauth2dev to v1.0.1 (#982)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-10 09:02:31 +00:00
renovate[bot]
37ad2fddd6 chore(deps): update dependency golang-version to v1.21.1 (#981)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-06 23:17:32 +00:00
renovate[bot]
8d8d9e3e4c fix(deps): update module golang.org/x/oauth2 to v0.12.0 (#979)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-06 01:03:45 +00:00
renovate[bot]
6737cae622 fix(deps): update module golang.org/x/net to v0.15.0 (#978)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-05 21:41:14 +00:00
renovate[bot]
c256bb9b0b fix(deps): update module golang.org/x/term to v0.12.0 (#976)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-03 19:08:26 +00:00
renovate[bot]
9151f23e71 fix(deps): update kubernetes packages to v0.28.1 (#974)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-24 19:37:23 +00:00
renovate[bot]
17d32369ce chore(deps): update dependency golangci/golangci-lint to v1.54.2 (#972)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-21 19:45:22 +00:00
renovate[bot]
8ff9fe5d0d fix(deps): update kubernetes packages to v0.28.0 (#971)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-16 03:06:01 +00:00
renovate[bot]
3ce908b35c chore(deps): update dependency golangci/golangci-lint to v1.54.1 (#970)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-11 18:09:47 +00:00
renovate[bot]
434be51543 chore(deps): update golang docker tag to v1.21 (#968)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-09 20:25:22 +00:00
renovate[bot]
2b68e5d59d chore(deps): update dependency golangci/golangci-lint to v1.54.0 (#969)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-09 17:33:48 +00:00
renovate[bot]
241d4cc2a9 chore(deps): update dependency golang-version to v1.21.0 (#967)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-08 19:07:47 +00:00
renovate[bot]
c3e4632fea fix(deps): update module github.com/chromedp/chromedp to v0.9.2 (#966)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-05 09:44:56 +00:00
renovate[bot]
d2ca6e68c0 fix(deps): update module golang.org/x/oauth2 to v0.11.0 (#965)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-05 07:48:45 +00:00
renovate[bot]
d1c871d1ff fix(deps): update module golang.org/x/net to v0.14.0 (#964)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-05 04:33:45 +00:00
renovate[bot]
68a121b949 fix(deps): update module golang.org/x/term to v0.11.0 (#963)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-04 18:17:00 +00:00
renovate[bot]
8497e548fc fix(deps): update module golang.org/x/net to v0.13.0 (#962)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-02 03:43:31 +00:00
renovate[bot]
87a98eb866 chore(deps): update dependency golang-version to v1.20.7 (#961)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-02 01:51:46 +00:00
renovate[bot]
9c63db7ba0 fix(deps): update kubernetes packages to v0.27.4 (#959)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-20 07:29:09 +00:00
renovate[bot]
243cfff790 chore(deps): update dependency golang-version to v1.20.6 (#957)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-11 18:57:51 +00:00
renovate[bot]
54faf5f306 fix(deps): update module golang.org/x/oauth2 to v0.10.0 (#955)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-06 01:30:16 +00:00
renovate[bot]
8549d219b0 fix(deps): update module golang.org/x/net to v0.12.0 (#953)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-05 19:41:43 +00:00
Hidetake Iwata
622dc5ba0b Refactor #944 (#951) 2023-06-24 15:26:39 +09:00
Reza Nikoopour
069ff68d99 Added flag to let user set redirect uri for authcode-keyboard (#944) 2023-06-23 16:53:55 +09:00
renovate[bot]
3d6784a336 chore(deps): update dependency golangci/golangci-lint to v1.53.3 (#949)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-15 14:49:40 +00:00
renovate[bot]
67dc859f0e fix(deps): update kubernetes packages to v0.27.3 (#948)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-15 07:37:34 +00:00
renovate[bot]
d8686babb0 fix(deps): update module golang.org/x/sync to v0.3.0 (#947)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-14 23:17:04 +00:00
renovate[bot]
7804f7240c fix(deps): update module golang.org/x/oauth2 to v0.9.0 (#946)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-14 18:42:06 +00:00
renovate[bot]
a99cad7890 fix(deps): update module golang.org/x/net to v0.11.0 (#945)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-14 16:57:50 +00:00
renovate[bot]
e1be9b5c7e chore(deps): update dependency golang-version to v1.20.5 (#940)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-06 22:22:57 +00:00
renovate[bot]
d9b10a46e3 chore(deps): update dependency golangci/golangci-lint to v1.53.2 (#939)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-03 18:38:33 +00:00
renovate[bot]
845dcd3f79 chore(deps): update dependency golangci/golangci-lint to v1.53.1 (#938)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-02 13:34:11 +00:00
renovate[bot]
fc496932e1 fix(deps): update module github.com/stretchr/testify to v1.8.4 (#937)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-30 13:09:48 +00:00
renovate[bot]
54372086fb fix(deps): update module github.com/stretchr/testify to v1.8.3 (#936)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-19 04:46:33 +00:00
renovate[bot]
d954d971a0 fix(deps): update kubernetes packages to v0.27.2 (#935)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-18 10:50:23 +00:00
renovate[bot]
9f1136cabc fix(deps): update module github.com/coreos/go-oidc/v3 to v3.6.0 (#934)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-17 00:05:07 +00:00
renovate[bot]
9e2fcd8cdb fix(deps): update module github.com/golang-jwt/jwt/v4 to v5 (#925)
* fix(deps): update module github.com/golang-jwt/jwt/v4 to v5

* Replace with `jwt.RegisteredClaims`

* Replace with `jwt.NewNumericDate`

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Hidetake Iwata <int128@gmail.com>
2023-05-14 21:38:48 +09:00
renovate[bot]
974369fe6f fix(deps): update module golang.org/x/oauth2 to v0.8.0 (#922) 2023-05-14 19:19:18 +09:00
Hidetake Iwata
8dc9f70407 Use setup-go@v4 and int128/go-workflows (#933) 2023-05-14 18:32:24 +09:00
Hidetake Iwata
10412effa2 Run go fmt (#866)
* Run go fmt

* Generated by GitHub Actions (go / generate)

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

---------

Co-authored-by: update-generated-files-action <41898282+github-actions[bot]@users.noreply.github.com>
2023-05-14 18:21:55 +09:00
renovate[bot]
269d8a48d4 fix(deps): update module golang.org/x/net to v0.10.0 (#932)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-08 22:07:55 +00:00
renovate[bot]
4ef50e884a fix(deps): update module golang.org/x/term to v0.8.0 (#930)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-05 01:28:43 +00:00
renovate[bot]
424cc24d15 fix(deps): update module golang.org/x/sync to v0.2.0 (#929)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-04 20:13:07 +00:00
renovate[bot]
18d06de10c fix(deps): update module k8s.io/klog/v2 to v2.100.1 (#927)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-03 02:03:28 +00:00
renovate[bot]
191b1ec7a3 chore(deps): update dependency golang-version to v1.20.4 (#928)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-02 23:30:46 +00:00
renovate[bot]
9b4ecec896 fix(deps): update kubernetes packages to v0.27.1 (#924)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-15 03:30:07 +00:00
renovate[bot]
004d7ca3f5 fix(deps): update kubernetes packages to v0.27.0 (#923)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-12 06:52:31 +00:00
renovate[bot]
dda70d881a fix(deps): update module golang.org/x/net to v0.9.0 (#921)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-07 01:25:02 +00:00
renovate[bot]
75e139b248 chore(deps): update dependency golang-version to v1.20.3 (#918)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-05 06:08:03 +00:00
renovate[bot]
66e05bbddf fix(deps): update module github.com/spf13/cobra to v1.7.0 (#919)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-05 00:51:46 +00:00
renovate[bot]
a5ec2e1252 chore(deps): update rajatjindal/krew-release-bot action to v0.0.46 (#915)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-26 15:38:20 +00:00
renovate[bot]
97e7a5c7c4 chore(deps): update rajatjindal/krew-release-bot action to v0.0.44 (#914)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-26 06:45:34 +00:00
renovate[bot]
727eeb8f7c chore(deps): update dependency golangci/golangci-lint to v1.52.2 (#913)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-25 23:33:00 +00:00
renovate[bot]
c96c931b83 chore(deps): update dependency golangci/golangci-lint to v1.52.1 (#912)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-22 02:57:24 +00:00
renovate[bot]
9a242e44d3 chore(deps): update dependency golangci/golangci-lint to v1.52.0 (#911)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-18 13:32:17 +00:00
renovate[bot]
124c558a6f fix(deps): update kubernetes packages to v0.26.3 (#910)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-18 07:04:14 +00:00
renovate[bot]
4df4f4132d fix(deps): update module github.com/chromedp/chromedp to v0.9.1 (#906)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-11 14:33:04 +00:00
renovate[bot]
a3d502e5d4 chore(deps): update dependency golang-version to v1.20.2 (#902)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-07 19:25:44 +00:00
renovate[bot]
5b7bf4b199 fix(deps): update module github.com/chromedp/chromedp to v0.8.8 (#901)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-05 15:27:50 +00:00
renovate[bot]
d1438615ac fix(deps): update module golang.org/x/oauth2 to v0.6.0 (#900)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-05 07:32:42 +00:00
renovate[bot]
435fe39c89 fix(deps): update module k8s.io/klog/v2 to v2.90.1 (#897)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-01 20:43:27 +00:00
renovate[bot]
b09e50d08d fix(deps): update kubernetes packages to v0.26.2 (#895)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-01 09:05:36 +00:00
renovate[bot]
e7f3b2c997 fix(deps): update module github.com/int128/oauth2dev to v1 (#896)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-01 15:08:29 +09:00
renovate[bot]
79cd9c53f8 fix(deps): update module github.com/stretchr/testify to v1.8.2 (#893)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-25 19:08:29 +00:00
renovate[bot]
ca2977a7e0 fix(deps): update github.com/int128/oauth2dev digest to 3709c53 (#890)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-20 12:12:23 +00:00
renovate[bot]
4c3a9f82f7 chore(deps): update dependency golangci/golangci-lint to v1.51.2 (#889)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-20 00:55:34 +00:00
renovate[bot]
d233ca1c20 fix(deps): update module github.com/golang-jwt/jwt/v4 to v4.5.0 (#888)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-19 16:41:06 +00:00
renovate[bot]
6377df181e fix(deps): update github.com/int128/oauth2dev digest to fd475b2 (#887)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-17 14:07:14 +00:00
Martin Linkhorst
f03d4fe821 get-token: add --force-refresh flag to refresh ID token (#879) 2023-02-17 15:25:11 +09:00
Hidetake Iwata
a049f321f1 Update renovate.json5 (#886) 2023-02-17 13:54:32 +09:00
renovate[bot]
1e650f52c9 fix(deps): update module golang.org/x/net to v0.7.0 (#884)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-15 14:26:45 +00:00
renovate[bot]
08f80581f2 fix(deps): update github.com/int128/oauth2dev digest to fe60e7d (#885)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-15 09:55:42 +00:00
renovate[bot]
a7b10d5a04 chore(deps): update dependency golang-version to v1.20.1 (#883)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-15 04:26:46 +00:00
renovate[bot]
0772812f03 fix(deps): update github.com/int128/oauth2dev digest to eaff031 (#882)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-13 02:07:25 +00:00
renovate[bot]
e32cdbf46b chore(deps): update dependency golang-version to v1.20.0 (#869)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-12 21:30:49 +00:00
renovate[bot]
9e6b8da46b chore(deps): update golang docker tag to v1.20 (#870)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-12 17:23:14 +00:00
Hidetake Iwata
f9a72bca0c Update renovate.json5 (#881) 2023-02-12 16:58:49 +09:00
renovate[bot]
792e737bc6 fix(deps): update github.com/int128/oauth2dev digest to efb5770 (#878)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-09 09:32:39 +00:00
renovate[bot]
6cdf48071a fix(deps): update module golang.org/x/net to v0.6.0 (#876)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-09 04:58:23 +00:00
renovate[bot]
5e12c3ee48 fix(deps): update module golang.org/x/term to v0.5.0 (#875)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-08 04:03:15 +00:00
renovate[bot]
c4219d6efd fix(deps): update github.com/int128/oauth2dev digest to 574d1a1 (#874)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-06 03:13:46 +00:00
renovate[bot]
8e23a2089c chore(deps): update dependency golangci/golangci-lint to v1.51.1 (#873)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-05 18:12:22 +00:00
renovate[bot]
965a7bb199 fix(deps): update github.com/int128/oauth2dev digest to abccf6b (#872)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-02 18:23:56 +00:00
renovate[bot]
9bb31d04b4 chore(deps): update dependency golangci/golangci-lint to v1.51.0 (#871)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-02 13:54:15 +00:00
renovate[bot]
8c755aa792 fix(deps): update module k8s.io/klog/v2 to v2.90.0 (#867)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-23 21:33:52 +00:00
renovate[bot]
5d7819cd7c fix(deps): update kubernetes packages to v0.26.1 (#864)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-19 09:58:57 +00:00
renovate[bot]
1b8e3750a4 fix(deps): update github.com/int128/oauth2dev digest to b478dfb (#861)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-11 05:04:36 +00:00
renovate[bot]
d87be5ec93 chore(deps): update dependency golang-version to v1.19.5 (#860)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-10 22:08:15 +00:00
renovate[bot]
145e6f907f fix(deps): update module github.com/chromedp/chromedp to v0.8.7 (#859)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-10 11:28:15 +00:00
renovate[bot]
c275178afe fix(deps): update github.com/int128/oauth2dev digest to c3e3a0f (#856)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-05 04:59:56 +00:00
renovate[bot]
d17fe6965f fix(deps): update module golang.org/x/oauth2 to v0.4.0 (#855)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-05 01:10:57 +00:00
renovate[bot]
b8a0317548 fix(deps): update module golang.org/x/net to v0.5.0 (#854)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-04 21:30:28 +00:00
Hidetake Iwata
5b3a605f10 Refactor with github.ref_name and github.ref_type (#853) 2023-01-04 09:34:00 +09:00
renovate[bot]
642195e7dd fix(deps): update module github.com/coreos/go-oidc/v3 to v3.5.0 (#852)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-03 22:52:11 +00:00
Hidetake Iwata
26733f68df Use actions/setup-go (#850) 2023-01-03 16:14:53 +09:00
renovate[bot]
7ee5296398 fix(deps): update module golang.org/x/net to v0.4.0 (#840)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-01 08:54:16 +00:00
renovate[bot]
fe267ef2ec fix(deps): update kubernetes packages to v0.26.0 (#843)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-01 06:27:30 +00:00
renovate[bot]
a925330117 fix(deps): update module github.com/golang-jwt/jwt/v4 to v4.4.3 (#836)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-01 04:05:34 +00:00
Hidetake Iwata
0976a226d3 Use int128/docker-build-workflow (#849) 2023-01-01 09:38:59 +09:00
Hidetake Iwata
adfbc48b24 Handle verification_url field in device flow (#846) 2022-12-24 19:10:21 +09:00
Hidetake Iwata
345465a5d3 Refactor test (#847) 2022-12-24 17:00:59 +09:00
Bastian
cda2eccaac feat(authentication): add oauth2 device grant (#837) 2022-12-22 08:03:10 +09:00
renovate[bot]
3aab0a575d chore(deps): update dependency golang-version to v1.19.4 (#842)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-07 21:31:58 +00:00
Hidetake Iwata
0dffdd7988 Use setup-go (#835) 2022-11-29 14:39:07 +09:00
Hidetake Iwata
bc6a86d002 Use setup-go cache (#834) 2022-11-29 11:49:31 +09:00
Hidetake Iwata
8b336ee2d5 Build multi-architecture image in parallel (#833)
* Build multi platforms in parallel

* Fix suffix

* docker pull

* Push [DO NOT MERGE]

* Add linux prefix

* Use int128/docker-manifest-create-action

* Fix latest

* Remove push
2022-11-20 21:30:28 +09:00
renovate[bot]
b640aa17df chore(deps): update module go to 1.19 (#751)
* chore(deps): update module go to 1.19

* Fix deprecations

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Hidetake Iwata <int128@gmail.com>
2022-11-19 21:45:08 +09:00
renovate[bot]
60f11875b1 chore(deps): update golang docker tag to v1.19 (#771)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-19 19:31:47 +09:00
renovate[bot]
b2303dde05 chore(deps): update dependency golang-version to v1.19.3 (#769)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-19 19:11:51 +09:00
Hidetake Iwata
1169cb534b refactor: replace io/ioutil with os, io package (#832) 2022-11-19 19:06:22 +09:00
renovate[bot]
9dfbe81b28 fix(deps): update module k8s.io/klog/v2 to v2.80.1 (#791)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-11 12:27:00 +00:00
renovate[bot]
0bdc92c218 fix(deps): update module golang.org/x/sync to v0.1.0 (#825)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-11 09:40:08 +00:00
renovate[bot]
d68ef508ac fix(deps): update module golang.org/x/oauth2 to v0.2.0 (#829)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-11 06:41:46 +00:00
renovate[bot]
e19d0404fd fix(deps): update module golang.org/x/net to v0.2.0 (#828)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-11 04:50:24 +00:00
renovate[bot]
dbd830b64f fix(deps): update module github.com/spf13/cobra to v1.6.1 (#818)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-11 03:02:12 +00:00
renovate[bot]
f722b2a40c fix(deps): update module github.com/coreos/go-oidc/v3 to v3.4.0 (#790)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-11 00:56:05 +00:00
renovate[bot]
7514789ace fix(deps): update kubernetes packages to v0.25.4 (#786)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-10 22:07:13 +00:00
renovate[bot]
3119e466c9 fix(deps): update module github.com/stretchr/testify to v1.8.1 (#827)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-10 20:02:21 +00:00
renovate[bot]
8d1d4d1c4b chore(deps): update dependency golangci/golangci-lint to v1.50.1 (#787)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-10 16:08:52 +00:00
renovate[bot]
1943ee0399 fix(deps): update golang.org/x/term digest to 8365914 (#824)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-10-17 23:59:30 +00:00
renovate[bot]
0a5671c135 fix(deps): update golang.org/x/net digest to f25eb7e (#823)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-10-17 20:52:28 +00:00
Huang Huang
3602948645 Correct the --listen-address flag at stage 2 instructions (#815) 2022-10-16 14:26:54 +09:00
renovate[bot]
bd2e7123ad fix(deps): update golang.org/x/oauth2 digest to 6fdb5e3 (#822)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-10-14 20:42:30 +00:00
renovate[bot]
934e27dd91 fix(deps): update golang.org/x/net digest to f15817d (#820)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-10-14 11:51:28 +00:00
renovate[bot]
24cf76feeb fix(deps): update golang.org/x/net digest to 0b7e1fb (#819)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-10-12 17:55:23 +00:00
renovate[bot]
051e5a8d52 fix(deps): update golang.org/x/oauth2 digest to b44042a (#816)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-10-06 19:58:04 +00:00
renovate[bot]
690ee40af0 fix(deps): update golang.org/x/net digest to 8021a29 (#814)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-10-04 21:20:37 +00:00
renovate[bot]
f742440099 fix(deps): update golang.org/x/net digest to bcab684 (#813)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-10-02 09:05:28 +00:00
renovate[bot]
7f37251846 fix(deps): update golang.org/x/net digest to 107f3e3 (#812)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-10-01 04:08:43 +00:00
renovate[bot]
e47ce9bd8c fix(deps): update module github.com/chromedp/chromedp to v0.8.6 (#811)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-10-01 00:36:46 +00:00
renovate[bot]
7a18b9c80d fix(deps): update golang.org/x/sync digest to 8fcdb60 (#810)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-09-30 01:06:33 +00:00
renovate[bot]
1b46377c31 fix(deps): update golang.org/x/net digest to f486391 (#809)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-09-27 23:56:09 +00:00
renovate[bot]
2f2f46382c fix(deps): update golang.org/x/net digest to 02166a9 (#806)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-09-27 01:08:20 +00:00
renovate[bot]
28c5da0b08 fix(deps): update golang.org/x/sync digest to 7f9b162 (#805)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-09-24 05:38:52 +00:00
renovate[bot]
fffb76284d fix(deps): update golang.org/x/net digest to 8be6392 (#804)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-09-24 02:55:33 +00:00
renovate[bot]
fe2ed1d7f1 fix(deps): update golang.org/x/net digest to d300de1 (#803)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-09-22 01:20:28 +00:00
renovate[bot]
0ee202bc50 fix(deps): update golang.org/x/net digest to d0c6ba3 (#802)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-09-21 01:05:17 +00:00
renovate[bot]
9d9b4f22c9 fix(deps): update golang.org/x/term digest to 7a66f97 (#801)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-09-20 11:38:41 +00:00
renovate[bot]
c9f1a9be18 fix(deps): update golang.org/x/net digest to f2f64eb (#800)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-09-20 06:04:35 +00:00
Mayur Waghmode
b43161531d Added ppc64le support (#799)
Signed-off-by: mayurwaghmode <waghmodemayur17@gmail.com>

Signed-off-by: mayurwaghmode <waghmodemayur17@gmail.com>
2022-09-12 18:49:03 +09:00
renovate[bot]
43c5283b3b fix(deps): update golang.org/x/net digest to bea034e (#797)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-09-09 20:37:10 +00:00
renovate[bot]
0a9a6a81f3 fix(deps): update module github.com/google/go-cmp to v0.5.9 (#795)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-09-09 08:38:06 +00:00
renovate[bot]
ec070a46f3 fix(deps): update golang.org/x/oauth2 digest to f213421 (#796)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-09-09 05:51:00 +00:00
renovate[bot]
0632078b7d fix(deps): update golang.org/x/sync digest to f12130a (#794)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-09-08 01:56:15 +00:00
renovate[bot]
44d0740937 fix(deps): update golang.org/x/net digest to 1e95f45 (#793)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-09-07 21:48:21 +00:00
renovate[bot]
523d07e83b fix(deps): update golang.org/x/net digest to f3363e0 (#792)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-09-06 21:30:45 +00:00
renovate[bot]
ffcb64ba74 fix(deps): update module github.com/chromedp/chromedp to v0.8.5 (#789)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-27 12:48:37 +00:00
renovate[bot]
a684112dd5 fix(deps): update golang.org/x/net digest to 83b083e (#788)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-26 19:52:41 +00:00
renovate[bot]
017b1b9fba fix(deps): update golang.org/x/oauth2 digest to 0ebed06 (#784)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-23 11:00:44 +00:00
renovate[bot]
5290ca9474 fix(deps): update golang.org/x/net digest to b0a4917 (#785)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-23 05:01:06 +00:00
renovate[bot]
542b454d1c fix(deps): update golang.org/x/sync digest to 7fc1605 (#783)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-19 06:06:49 +00:00
renovate[bot]
ba1beb0b10 fix(deps): update kubernetes packages to v0.24.4 (#782)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-18 09:31:51 +00:00
renovate[bot]
8a2837d0ff fix(deps): update module github.com/chromedp/chromedp to v0.8.4 (#779)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-14 10:38:20 +00:00
renovate[bot]
a04131280e fix(deps): update golang.org/x/net digest to 3211cb9 (#778)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-12 21:57:19 +00:00
renovate[bot]
ccaf76f370 fix(deps): update golang.org/x/net digest to 13a9a73 (#777)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-11 21:54:48 +00:00
renovate[bot]
7537256308 fix(deps): update golang.org/x/net digest to 07c6da5 (#776)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-09 22:44:49 +00:00
renovate[bot]
cd68981c75 fix(deps): update golang.org/x/net digest to f428fae (#775)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-09 05:54:24 +00:00
renovate[bot]
e3934f5e3b fix(deps): update golang.org/x/oauth2 digest to 8227340 (#774)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-08 22:08:06 +00:00
renovate[bot]
1bd1fc9079 chore(deps): update dependency golangci/golangci-lint to v1.48.0 (#772) 2022-08-06 11:23:20 +09:00
renovate[bot]
63c9018faa fix(deps): update golang.org/x/net digest to a33c5aa (#773)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-05 04:48:31 +00:00
renovate[bot]
d6f30063bd fix(deps): update golang.org/x/net digest to 0bcc04d (#770)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-03 02:29:18 +00:00
renovate[bot]
572eaed609 chore(deps): update dependency golangci/golangci-lint to v1.47.3 (#768)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-02 01:57:48 +00:00
renovate[bot]
2757feda35 chore(deps): update dependency golang-version to v1.18.5 (#767)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-08-01 21:35:30 +00:00
Marko Mikulicic
7bcc15827a Use cgo when cross-compiling macos arm64 (#763) 2022-07-29 12:56:36 +09:00
renovate[bot]
0b53136d12 fix(deps): update golang.org/x/net digest to c7608f3 (#766)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-29 01:05:14 +00:00
renovate[bot]
4642e559d4 fix(deps): update golang.org/x/net digest to 1f511ac (#765)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-28 17:38:34 +00:00
renovate[bot]
de66e882b3 fix(deps): update golang.org/x/net digest to 41545e8 (#764)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-28 05:53:33 +00:00
renovate[bot]
4055aeaaa4 fix(deps): update golang.org/x/net digest to 0699458 (#761)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-27 04:04:47 +00:00
renovate[bot]
51d38d6937 fix(deps): update module github.com/chromedp/chromedp to v0.8.3 (#760)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-26 03:00:46 +00:00
renovate[bot]
88729027f1 fix(deps): update golang.org/x/net digest to 46097bf (#759)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-26 00:51:33 +00:00
renovate[bot]
96354ebfb9 fix(deps): update golang.org/x/term digest to a9ba230 (#758)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-23 02:08:15 +00:00
renovate[bot]
c01bbe3110 fix(deps): update golang.org/x/sync digest to 886fb93 (#730)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-22 23:52:26 +00:00
renovate[bot]
75c24e8a25 fix(deps): update golang.org/x/oauth2 digest to 128564f (#756)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-22 21:33:03 +00:00
renovate[bot]
7b824e6e20 fix(deps): update golang.org/x/net digest to a158d28 (#755)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-22 19:40:46 +00:00
renovate[bot]
fda2fe3775 chore(deps): update dependency golangci/golangci-lint to v1.47.2 (#752)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-21 16:12:08 +00:00
renovate[bot]
a13e6ecf5d chore(deps): update dependency golangci/golangci-lint to v1.47.1 (#750)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-19 17:09:16 +00:00
renovate[bot]
cbc4a5a4c6 fix(deps): update golang.org/x/oauth2 digest to c8730f7 (#749)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-18 22:44:53 +00:00
renovate[bot]
696b630950 fix(deps): update kubernetes packages to v0.24.3 (#675)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-18 21:09:11 +00:00
renovate[bot]
55af8ab1d1 chore(deps): update dependency golangci/golangci-lint to v1.47.0 (#748)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-18 18:41:37 +00:00
renovate[bot]
7b1597de54 fix(deps): update golang.org/x/term digest to 065cf7b (#721)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-18 15:53:33 +00:00
renovate[bot]
6510482278 fix(deps): update golang.org/x/net digest to 1185a90 (#670)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-18 12:22:08 +00:00
renovate[bot]
da6d8f9467 chore(deps): update docker/setup-buildx-action action to v2 (#746) 2022-07-18 16:11:53 +09:00
renovate[bot]
37c602fc73 chore(deps): update docker/setup-qemu-action action to v2 (#747) 2022-07-18 16:06:21 +09:00
renovate[bot]
78808eed97 chore(deps): update docker/metadata-action action to v4 (#745) 2022-07-18 15:57:23 +09:00
renovate[bot]
66592b5831 fix(deps): update module github.com/alexflint/go-filemutex to v1.2.0 (#712)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-18 14:17:34 +09:00
renovate[bot]
cc323d2fae chore(deps): update docker/build-push-action action to v3 (#743)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-18 14:17:16 +09:00
renovate[bot]
1829e2caaa chore(deps): update docker/login-action action to v2 (#744)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-18 14:17:06 +09:00
renovate[bot]
cc30f40e58 fix(deps): update module k8s.io/klog/v2 to v2.70.1 (#742)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-18 13:58:12 +09:00
renovate[bot]
6037d5706a fix(deps): update golang.org/x/oauth2 digest to 2104d58 (#693)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-18 13:57:41 +09:00
renovate[bot]
d67e2663c9 fix(deps): update module github.com/spf13/cobra to v1.5.0 (#741)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-18 13:57:19 +09:00
renovate[bot]
1fe770939a fix(deps): update module github.com/golang-jwt/jwt/v4 to v4.4.2 (#715)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-18 13:05:24 +09:00
Hidetake Iwata
5ba7f551cf Refactor tests (#740)
* refactor: use t.Setenv()

* refactor: use t.TempDir()

* refactor: use t.Cleanup()
2022-07-16 22:08:55 +09:00
renovate[bot]
5ea4d3648a chore(deps): update dependency golang-version to v1.18.4 (#720)
* chore(deps): update dependency golang-version to v1.18.4

* Bump github.com/json-iterator/go to v1.1.12

https://github.com/json-iterator/go/releases/tag/v1.1.12

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Hidetake Iwata <int128@gmail.com>
2022-07-16 21:05:23 +09:00
renovate[bot]
41f31cd056 fix(deps): update module github.com/coreos/go-oidc/v3 to v3.2.0 (#738)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-16 20:41:08 +09:00
Hidetake Iwata
7152bccd21 refactor: migrate to Testify Mock (#739) 2022-07-16 16:55:51 +09:00
renovate[bot]
e27b5723da fix(deps): update module github.com/chromedp/chromedp to v0.8.2 (#726)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-07-16 13:10:42 +09:00
renovate[bot]
5499a35916 chore(deps): update dependency golangci/golangci-lint to v1.46.2 (#735)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-07-16 13:10:02 +09:00
Hidetake Iwata
86341c82fb Use int128/go-actions/setup (#731) 2022-05-21 16:40:56 +09:00
renovate[bot]
a028255661 fix(deps): update module github.com/google/go-cmp to v0.5.8 (#724) 2022-05-21 16:27:07 +09:00
Hidetake Iwata
3679e5e436 Update runner of system-test to ubuntu-latest (#509) 2022-05-21 14:28:30 +09:00
Hidetake Iwata
ed723fed2a Fix authentication error in system-test (#729)
* Show log of kube-apiserver

* Fix kubeadmConfigPatches
2022-05-21 13:57:06 +09:00
renovate[bot]
98b1fb92f1 chore(deps): update actions/cache action to v3 (#710)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-05-07 17:28:16 +09:00
Hidetake Iwata
d28cecd756 Use int128/renovate-base (#725) 2022-05-07 17:27:04 +09:00
renovate[bot]
4ba848019a chore(deps): update rajatjindal/krew-release-bot action to v0.0.43 (#723)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-04-17 05:18:25 +00:00
renovate[bot]
03a1b10c3c chore(deps): update rajatjindal/krew-release-bot action to v0.0.42 (#716)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-03-29 11:03:58 +00:00
renovate[bot]
03322d0cad chore(deps): update dependency golangci/golangci-lint to v1.45.2 (#714)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-03-24 16:18:40 +00:00
renovate[bot]
58ee2725e9 chore(deps): update dependency golangci/golangci-lint to v1.45.1 (#713)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-03-24 11:23:43 +00:00
renovate[bot]
8572c8db95 fix(deps): update module github.com/chromedp/chromedp to v0.8.0 (#709)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-03-21 12:15:04 +00:00
renovate[bot]
ff6e770818 fix(deps): update module k8s.io/klog/v2 to v2.60.1 (#708)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-03-20 18:27:45 +00:00
renovate[bot]
1a58259fc0 chore(deps): update dependency golangci/golangci-lint to v1.45.0 (#707)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-03-18 19:59:14 +00:00
renovate[bot]
1c37d7a8b7 fix(deps): update module k8s.io/klog/v2 to v2.60.0 (#705)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-03-17 17:27:21 +00:00
renovate[bot]
4be2ac025a fix(deps): update module github.com/golang-jwt/jwt/v4 to v4.4.0 (#704)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-03-17 05:22:31 +00:00
renovate[bot]
adb57bdb36 fix(deps): update module k8s.io/klog/v2 to v2.50.2 (#703)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-03-17 02:35:59 +00:00
renovate[bot]
1166672b92 fix(deps): update module k8s.io/klog/v2 to v2.50.1 (#702)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-03-16 17:29:05 +00:00
renovate[bot]
c08bedfcbd chore(deps): update dependency golang to v1.18 (#700)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-03-16 03:50:28 +00:00
renovate[bot]
72237142c8 fix(deps): update module k8s.io/klog/v2 to v2.50.0 (#699)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-03-16 01:32:13 +00:00
renovate[bot]
aa727c424a chore(deps): update golangci/golangci-lint-action action to v3 (#695)
* chore(deps): update golangci/golangci-lint-action action to v3

* Update go.yaml

Co-authored-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: Hidetake Iwata <int128@gmail.com>
2022-03-12 16:36:09 +09:00
renovate[bot]
92cb984154 chore(deps): update actions/setup-go action to v3 (#696)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-03-12 16:29:56 +09:00
renovate[bot]
86fc4df483 fix(deps): update module github.com/spf13/cobra to v1.4.0 (#698)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-03-11 17:42:17 +00:00
renovate[bot]
c931677964 chore(deps): update actions/checkout action to v3 (#697)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-03-04 19:12:00 +09:00
renovate[bot]
8b0a087e14 fix(deps): update module github.com/chromedp/chromedp to v0.7.8 (#691)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-02-19 05:01:48 +00:00
renovate[bot]
713696ce12 chore(deps): update dependency golangci/golangci-lint to v1.44.2 (#690)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-02-18 00:42:56 +00:00
renovate[bot]
0f281e8bb6 chore(deps): update dependency golangci/golangci-lint to v1.44.1 (#689)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-02-17 15:00:53 +00:00
renovate[bot]
64c0f56480 fix(deps): update module github.com/golang-jwt/jwt/v4 to v4.3.0 (#687)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-02-10 08:28:01 +00:00
renovate[bot]
71076214ce fix(deps): update module github.com/chromedp/chromedp to v0.7.7 (#686)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-02-04 11:39:14 +00:00
renovate[bot]
46b5961742 chore(deps): update dependency golangci/golangci-lint to v1.44.0 (#684)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-01-25 13:16:01 +00:00
renovate[bot]
2675df15d4 fix(deps): update module github.com/google/go-cmp to v0.5.7 (#682)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2022-01-22 15:25:59 +00:00
Hidetake Iwata
b17843ce7b Update README.md 2022-01-22 22:03:43 +09:00
Hidetake Iwata
775841a72b Remove deprecation of standalone mode (#680)
* Remove deprecation of standalone mode

* Update standalone-mode.md
2022-01-08 17:48:00 +09:00
renovate[bot]
564177cd18 fix(deps): update module k8s.io/klog/v2 to v2.40.1 (#679)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-12-19 04:11:07 +00:00
renovate[bot]
3f5514573d fix(deps): update module k8s.io/klog/v2 to v2.40.0 (#678)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-12-17 16:41:23 +00:00
renovate[bot]
a70c0e21b9 fix(deps): update module github.com/spf13/cobra to v1.3.0 (#677)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-12-14 23:53:29 +00:00
renovate[bot]
6a8dd65a1a fix(deps): update module github.com/golang-jwt/jwt/v4 to v4.2.0 (#672)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-12-03 20:38:18 +00:00
renovate[bot]
6b5947b174 chore(deps): update dependency golangci/golangci-lint to v1.43.0 (#669)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-11-28 07:10:52 +00:00
Hidetake Iwata
6ff75291d7 Use Renovate config in int128/go-actions 2021-11-28 15:44:45 +09:00
Hidetake Iwata
3cb6988b8b Refactor workflows (#668)
* Refactor workflows

* Fix runs-on

* Fix Dockerfile
2021-11-28 15:10:23 +09:00
renovate[bot]
2a14902541 fix(deps): update module github.com/chromedp/chromedp to v0.7.6 (#667)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-11-27 04:25:47 +00:00
renovate[bot]
78d9d1f913 fix(deps): update golang.org/x/net commit hash to d83791d (#666)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-11-23 23:03:26 +00:00
renovate[bot]
9f39c00cc8 fix(deps): update module k8s.io/client-go to v0.22.4 (#663)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-11-18 21:14:24 +00:00
renovate[bot]
6c767e8545 fix(deps): update golang.org/x/net commit hash to 6a13c67 (#664)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-11-18 18:27:01 +00:00
renovate[bot]
ccb00b7b58 fix(deps): update module k8s.io/apimachinery to v0.22.4 (#662)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-11-18 04:48:38 +00:00
renovate[bot]
cf8b89d6ae fix(deps): update golang.org/x/oauth2 commit hash to d3ed0bb (#661)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-11-17 03:58:13 +00:00
renovate[bot]
86a8721cac fix(deps): update golang.org/x/net commit hash to 47ca1ff (#660)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-11-17 01:37:59 +00:00
renovate[bot]
5f2ae5497f Merge pull request #657 from int128/renovate/k8s.io-client-go-0.x
fix(deps): update module k8s.io/client-go to v0.22.3
2021-10-28 10:29:01 +00:00
Renovate Bot
e89de7de0f fix(deps): update module k8s.io/client-go to v0.22.3 2021-10-28 10:28:26 +00:00
renovate[bot]
fd5580861f Merge pull request #656 from int128/renovate/k8s.io-apimachinery-0.x
fix(deps): update module k8s.io/apimachinery to v0.22.3
2021-10-28 10:26:21 +00:00
Renovate Bot
4382333ac9 fix(deps): update module k8s.io/apimachinery to v0.22.3 2021-10-28 10:26:17 +00:00
renovate[bot]
821265c912 fix(deps): update module k8s.io/klog/v2 to v2.30.0 (#654)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-10-22 15:17:05 +00:00
renovate[bot]
f5f0c7eadd fix(deps): update golang.org/x/net commit hash to d418f37 (#653)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-10-20 09:47:35 +00:00
Hidetake Iwata
b1af578679 Fix docker push error 2021-10-20 12:20:53 +09:00
renovate[bot]
5737f96665 fix(deps): update golang.org/x/net commit hash to c6ed85c (#652)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-10-20 02:08:53 +00:00
renovate[bot]
07129f8c77 fix(deps): update golang.org/x/net commit hash to 4f30a5c (#651)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-10-15 22:57:15 +00:00
renovate[bot]
931d4f3a89 fix(deps): update golang.org/x/net commit hash to fd004c5 (#650)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-10-15 01:31:08 +00:00
renovate[bot]
f76e186d72 fix(deps): update golang.org/x/net commit hash to 2b766c0 (#649)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-10-14 20:01:03 +00:00
renovate[bot]
3e44d7655f fix(deps): update golang.org/x/net commit hash to e13a265 (#648)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-10-13 20:13:11 +00:00
renovate[bot]
14f57e7232 fix(deps): update golang.org/x/net commit hash to ee2e9a0 (#647)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-10-13 16:48:16 +00:00
renovate[bot]
af8ae6f2f6 fix(deps): update module github.com/int128/oauth2cli to v1.14.0 (#646)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-10-12 02:40:53 +00:00
renovate[bot]
83a4524487 fix(deps): update golang.org/x/net commit hash to caeb26a (#645)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-10-11 18:40:20 +00:00
renovate[bot]
aeda430a1f fix(deps): update golang.org/x/net commit hash to 3b03d30 (#644)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-10-08 21:53:21 +00:00
renovate[bot]
10fdb63be3 fix(deps): update golang.org/x/net commit hash to 59d4e92 (#643)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-10-07 17:24:54 +00:00
renovate[bot]
fb439187d3 fix(deps): update golang.org/x/net commit hash to 62292e8 (#642)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-10-06 21:05:48 +00:00
renovate[bot]
73359e62db fix(deps): update golang.org/x/net commit hash to d2e5035 (#641)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-10-06 00:05:56 +00:00
renovate[bot]
c38b41cf85 fix(deps): update golang.org/x/oauth2 commit hash to 6b3c2da (#640)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-10-05 19:59:18 +00:00
renovate[bot]
e149f6443f fix(deps): update module github.com/golang-jwt/jwt/v4 to v4.1.0 (#636)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-10-05 13:35:11 +00:00
renovate[bot]
3c0bca7dee fix(deps): update golang.org/x/term commit hash to 03fcf44 (#637)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-10-05 11:33:50 +00:00
renovate[bot]
43497466f9 fix(deps): update golang.org/x/net commit hash to d4b1ae0 (#635)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-10-05 09:25:27 +00:00
Hidetake Iwata
0075043866 Use int128/docker-build-cache-config-action (#639) 2021-10-05 16:33:30 +09:00
renovate[bot]
b160aea35e fix(deps): update golang.org/x/net commit hash to 3c21e5b (#634)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-09-17 19:13:50 +00:00
renovate[bot]
52311525fe fix(deps): update module k8s.io/client-go to v0.22.2 (#632)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-09-17 17:31:25 +00:00
renovate[bot]
ab923d0d49 fix(deps): update module k8s.io/apimachinery to v0.22.2 (#631)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-09-17 16:05:50 +00:00
renovate[bot]
97908c775f fix(deps): update module github.com/coreos/go-oidc/v3 to v3.1.0 (#630)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-09-17 10:16:07 +00:00
renovate[bot]
c6662f32fb fix(deps): update golang.org/x/term commit hash to 140adaa (#629)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-09-17 00:08:20 +00:00
renovate[bot]
a07a1eb7e8 fix(deps): update golang.org/x/net commit hash to 12bc252 (#626)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-09-16 04:35:33 +00:00
renovate[bot]
f5f73df697 fix(deps): update github.com/pkg/browser commit hash to 681adbf (#625)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-09-11 10:11:49 +00:00
renovate[bot]
ae3a001dd2 fix(deps): update golang.org/x/net commit hash to a5e0955 (#624)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-09-08 21:19:10 +00:00
renovate[bot]
eb8f211e67 fix(deps): update golang.org/x/net commit hash to ff17edf (#623)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-09-08 00:40:24 +00:00
Hidetake Iwata
237e53313d Add flag to set custom browser command (#622)
* Add flag to set custom browser command

* Use --browser-command in system_test

* Add --browser-command= to setup message
2021-09-05 11:35:03 +09:00
renovate[bot]
8cce70c302 fix(deps): update github.com/pkg/browser commit hash to 6d279e1 (#621)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-09-04 02:44:53 +00:00
renovate[bot]
751b62b418 fix(deps): update golang.org/x/net commit hash to ad29c8a (#620)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-09-03 19:31:19 +00:00
renovate[bot]
1aeb6b0c0d fix(deps): update golang.org/x/net commit hash to 8d99171 (#619)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-09-02 19:08:13 +00:00
renovate[bot]
58d354f6bc fix(deps): update module k8s.io/klog/v2 to v2.20.0 (#618)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-09-02 07:32:31 +00:00
Hidetake Iwata
077d9ab90c Use docker/metadata-action@v3 (#616) 2021-08-28 22:10:41 +09:00
Joel Kaasinen
50bc986085 update README.md (#615) 2021-08-28 08:03:20 +09:00
renovate[bot]
75698aee0c fix(deps): update golang.org/x/net commit hash to e898025 (#613)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-08-25 19:59:14 +00:00
renovate[bot]
a17137b4e9 fix(deps): update module k8s.io/client-go to v0.22.1 (#612)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-08-20 00:16:31 +00:00
renovate[bot]
395a36eb53 fix(deps): update module k8s.io/apimachinery to v0.22.1 (#611)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-08-19 22:44:00 +00:00
renovate[bot]
b86118034f fix(deps): update golang.org/x/oauth2 commit hash to 2bc19b1 (#610)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-08-19 21:04:49 +00:00
renovate[bot]
a4b63da790 fix(deps): update golang.org/x/oauth2 commit hash to 7df4dd6 (#609)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-08-18 02:05:49 +00:00
renovate[bot]
b0d9ff907b chore(deps): update golang docker tag to v1.17 (#608)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-08-17 04:36:40 +00:00
renovate[bot]
c8d7fa5009 fix(deps): update golang.org/x/oauth2 commit hash to faf39c7 (#606)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-08-13 20:13:09 +00:00
renovate[bot]
99fc66e205 fix(deps): update golang.org/x/net commit hash to 60bc85c (#607)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-08-13 18:16:01 +00:00
Hidetake Iwata
33275b0a30 Export BuildKit cache to GHCR (#605) 2021-08-09 22:53:48 +09:00
Hidetake Iwata
9a850d7072 Migrate to github.com/golang-jwt/jwt/v4 (#604) 2021-08-08 11:39:45 +09:00
renovate[bot]
e5981c49c8 chore(deps): update codecov/codecov-action action to v2 (#595) 2021-08-08 10:51:03 +09:00
renovate[bot]
226683c051 fix(deps): update golang.org/x/oauth2 commit hash to 6f1e639 (#602)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-08-05 20:23:53 +00:00
renovate[bot]
3d6cfe5054 fix(deps): update golang.org/x/net commit hash to aaa1db6 (#603)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-08-05 19:35:51 +00:00
renovate[bot]
8cba4b4647 fix(deps): update module k8s.io/client-go to v0.22.0 (#601)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-08-04 23:32:41 +00:00
renovate[bot]
f1b17d2fc1 fix(deps): update module k8s.io/apimachinery to v0.22.0 (#600)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-08-04 22:57:35 +00:00
Pedro Kiefer
a0cfde7198 refactor: add --oidc-use-pkce flag to force PKCE authorization flow (#599) 2021-08-04 06:38:26 +09:00
renovate[bot]
680dfeea68 fix(deps): update golang.org/x/net commit hash to c6fcb2d (#598)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-07-26 23:54:50 +00:00
renovate[bot]
103451e68d fix(deps): update golang.org/x/net commit hash to 853a461 (#594)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-07-16 21:48:03 +00:00
renovate[bot]
480c8305b1 fix(deps): update module k8s.io/client-go to v0.21.3 (#593)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-07-16 09:00:36 +00:00
renovate[bot]
e472a4b261 fix(deps): update module k8s.io/apimachinery to v0.21.3 (#592)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-07-16 07:51:53 +00:00
renovate[bot]
849bf27c09 fix(deps): update module k8s.io/klog/v2 to v2.10.0 (#591)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-07-15 11:13:45 +00:00
renovate[bot]
b5462d49ad fix(deps): update module github.com/chromedp/chromedp to v0.7.4 (#589)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-07-13 08:52:17 +00:00
renovate[bot]
08fdfa8a61 fix(deps): update github.com/pkg/browser commit hash to 7d21f8c (#588)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-07-06 15:47:15 +00:00
renovate[bot]
d10adc61cf fix(deps): update module github.com/spf13/cobra to v1.2.1 (#587)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-07-02 16:36:21 +00:00
renovate[bot]
9ecf09d7bc fix(deps): update module github.com/spf13/cobra to v1.2.0 (#586)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-07-01 19:22:49 +00:00
renovate[bot]
d92802565d chore(deps): update rajatjindal/krew-release-bot action to v0.0.40 (#583)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-06-28 21:25:12 +00:00
renovate[bot]
14c55a1312 fix(deps): update golang.org/x/oauth2 commit hash to a41e5a7 (#585)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-06-28 20:09:04 +00:00
renovate[bot]
aa912cf6d0 fix(deps): update golang.org/x/oauth2 commit hash to a8dc77f (#582)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-06-22 22:26:23 +00:00
renovate[bot]
7e15541455 fix(deps): update golang.org/x/oauth2 commit hash to bce0382 (#581)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-06-22 20:21:24 +00:00
renovate[bot]
eb205ebbe8 fix(deps): update golang.org/x/oauth2 commit hash to 14747e6 (#580)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-06-22 18:49:24 +00:00
renovate[bot]
dc5cc7e7ad fix(deps): update github.com/pkg/browser commit hash to c198bc9 (#579)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-06-21 11:06:17 +00:00
renovate[bot]
06fa24bcee fix(deps): update module k8s.io/client-go to v0.21.2 (#578)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-06-18 02:31:09 +00:00
renovate[bot]
e5469925f5 fix(deps): update module k8s.io/apimachinery to v0.21.2 (#577)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-06-18 01:14:34 +00:00
renovate[bot]
6dbd197e8c fix(deps): update golang.org/x/oauth2 commit hash to d040287 (#576)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-06-15 20:28:06 +00:00
renovate[bot]
0e10951907 fix(deps): update golang.org/x/term commit hash to 6886f2d (#575)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-06-15 18:15:51 +00:00
renovate[bot]
b23f036445 fix(deps): update golang.org/x/net commit hash to 04defd4 (#573)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-06-14 20:00:31 +00:00
renovate[bot]
63f08f2f7a fix(deps): update module github.com/golang/mock to v1.6.0 (#572)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-06-11 23:01:45 +00:00
renovate[bot]
2006d13375 fix(deps): update golang.org/x/net commit hash to 84b48f8 (#571)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-06-10 15:28:35 +00:00
renovate[bot]
fb4d9663d5 fix(deps): update golang.org/x/net commit hash to 52da8fb (#570)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-06-10 13:26:15 +00:00
Hidetake Iwata
82e96fba84 Explicitly set CGO_ENABLED on build (#569) 2021-06-07 13:04:39 +09:00
renovate[bot]
8a725104e1 fix(deps): update github.com/pkg/browser commit hash to a7b7a61 (#568)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-06-07 01:18:44 +00:00
renovate[bot]
96d6492825 fix(deps): update module github.com/chromedp/chromedp to v0.7.3 (#566)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-05-27 08:08:35 +00:00
renovate[bot]
f40dc4c409 fix(deps): update module k8s.io/klog/v2 to v2.9.0 (#565)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-05-26 13:11:29 +00:00
renovate[bot]
7b9bb9e479 fix(deps): update golang.org/x/net commit hash to abc4532 (#564)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-05-25 09:34:54 +00:00
renovate[bot]
f0cb7ec1eb fix(deps): update module github.com/google/go-cmp to v0.5.6 (#563)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-05-25 04:58:38 +00:00
renovate[bot]
973674300e fix(deps): update golang.org/x/net commit hash to fe42d45 (#560)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-05-21 21:42:14 +00:00
renovate[bot]
0479bf6c68 fix(deps): update module k8s.io/client-go to v0.21.1 (#557)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-05-19 12:46:40 +00:00
renovate[bot]
93f2c88644 fix(deps): update module k8s.io/apimachinery to v0.21.1 (#556)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-05-19 11:05:03 +00:00
Suraj Banakar(बानकर) | スラジ
966e612b14 Update README.md (#558) 2021-05-19 17:50:48 +09:00
renovate[bot]
7a4099ed65 fix(deps): update golang.org/x/net commit hash to 4163338 (#554)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-05-14 19:23:02 +00:00
renovate[bot]
62e3d07d18 fix(deps): update golang.org/x/oauth2 commit hash to f6687ab (#555)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-05-14 18:13:42 +00:00
renovate[bot]
92fe0f1c3f fix(deps): update golang.org/x/net commit hash to 81045d8 (#553)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-05-10 11:37:56 +00:00
renovate[bot]
0903aa5636 fix(deps): update golang.org/x/net commit hash to 16afe75 (#551)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-05-09 01:03:58 +00:00
renovate[bot]
3338116bfb fix(deps): update module github.com/chromedp/chromedp to v0.7.2 (#552)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-05-08 23:22:53 +00:00
Hidetake Iwata
d0364f0942 Fix "~" is not expanded on Windows (#550)
* Run tests on macOS and Windows

* Use filepath and client-go/util/homedir package
2021-05-04 11:12:10 +09:00
renovate[bot]
ea78452b52 fix(deps): update golang.org/x/term commit hash to a79de54 (#549)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-05-03 10:11:02 +00:00
renovate[bot]
2d52355a37 fix(deps): update golang.org/x/net commit hash to 7fd8e65 (#548)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-05-03 08:49:41 +00:00
renovate[bot]
98895d12e9 fix(deps): update module github.com/chromedp/chromedp to v0.7.1 (#544)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-05-02 03:06:10 +00:00
renovate[bot]
bfac26d6d6 fix(deps): update golang.org/x/term commit hash to c04ba85 (#547)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-05-02 01:52:59 +00:00
renovate[bot]
a784b7a60b fix(deps): update golang.org/x/oauth2 commit hash to 81ed05c (#545)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-05-02 01:00:41 +00:00
renovate[bot]
2702f9259e fix(deps): update golang.org/x/net commit hash to f8dd838 (#546)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-05-02 00:05:03 +00:00
renovate[bot]
edf1bd705b fix(deps): update golang.org/x/net commit hash to 5f58ad6 (#542)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-04-23 22:23:22 +00:00
renovate[bot]
d8ab06b0a4 fix(deps): update golang.org/x/term commit hash to f5beecf (#541)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-04-22 15:16:49 +00:00
renovate[bot]
e1bb47bad2 fix(deps): update golang.org/x/net commit hash to 4e50805 (#540)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-04-22 02:21:55 +00:00
renovate[bot]
8dce91cc2d fix(deps): update golang.org/x/term commit hash to b80969c (#539)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-04-22 00:12:49 +00:00
renovate[bot]
415a52bc68 fix(deps): update golang.org/x/net commit hash to 798c215 (#538)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-04-20 23:01:52 +00:00
renovate[bot]
d20ceb5262 fix(deps): update golang.org/x/net commit hash to d25e304 (#537)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-04-20 11:31:08 +00:00
Hidetake Iwata
4ca11f13ac Add .exe extension to Windows distribution (#534) 2021-04-17 14:50:58 +09:00
Peter Holko (Ping Identity)
0b6d34e1a2 Update setup.md (#532)
Adding Ping Identity section to the setup guide
2021-04-17 14:05:28 +09:00
renovate[bot]
79882f6e3a fix(deps): update module k8s.io/client-go to v0.21.0 (#529)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-04-16 14:56:09 +00:00
renovate[bot]
f66835b04e fix(deps): update module k8s.io/apimachinery to v0.21.0 (#528)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-04-16 11:07:26 +00:00
renovate[bot]
487bbe7c9c fix(deps): update golang.org/x/term commit hash to 72f3dc4 (#527)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-04-16 09:01:43 +00:00
renovate[bot]
30a961dbd1 fix(deps): update golang.org/x/oauth2 commit hash to 5e61552 (#531)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-04-16 04:48:12 +00:00
renovate[bot]
1460c8158f fix(deps): update golang.org/x/net commit hash to e915ea6 (#530)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-04-16 02:45:13 +00:00
renovate[bot]
33f62ff368 fix(deps): update golang.org/x/net commit hash to a5a99cb (#525)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-04-05 20:18:16 +00:00
renovate[bot]
9668d0f057 fix(deps): update golang.org/x/oauth2 commit hash to 2e8d934 (#526)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-04-02 18:25:01 +00:00
renovate[bot]
5532f16f42 fix(deps): update golang.org/x/net commit hash to cb1fcc7 (#524)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-03-31 09:06:10 +00:00
renovate[bot]
add68e27e5 fix(deps): update golang.org/x/oauth2 commit hash to 22b0ada (#520)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-03-31 02:08:50 +00:00
renovate[bot]
bddce9d830 fix(deps): update golang.org/x/net commit hash to e572328 (#523)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-03-31 00:24:08 +00:00
renovate[bot]
7c2b049e5d fix(deps): update golang.org/x/net commit hash to cd0ac97 (#521)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-03-30 21:50:37 +00:00
Hidetake Iwata
9e354b4fe5 Build image on pull request (#522) 2021-03-28 12:52:12 +09:00
renovate[bot]
835ad7ad55 fix(deps): update module github.com/chromedp/chromedp to v0.6.10 (#518)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-03-24 12:26:07 +00:00
renovate[bot]
1e0b070f57 fix(deps): update golang.org/x/net commit hash to 2c4c8ec (#519)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-03-24 10:57:43 +00:00
Hidetake Iwata
0ccccbcb36 Do not build image on pull request (#516) 2021-03-22 14:07:08 +09:00
Hidetake Iwata
02ad24e6fe Update README.md 2021-03-22 13:49:27 +09:00
Hidetake Iwata
c011fef38c Delete .circleci directory 2021-03-22 13:48:04 +09:00
Hidetake Iwata
822ea91d21 Delete dist directory 2021-03-22 13:47:04 +09:00
Hidetake Iwata
6322b6e1fb Fix krew release (#515)
* Fix .krew.yaml

time="2021-03-22T04:06:39Z" level=fatal msg="template: .krew.yaml:28:9: executing \".krew.yaml\" at <addURIAndSha \"https://github.com/int128/kubelogin/releases/download/{{ TagName }}/kubelogin_linux_amd64.zip\" .TagName>: error calling addURIAndSha: template: url:1: function \"TagName\" not defined"

* Fix indent error
2021-03-22 13:39:51 +09:00
renovate[bot]
fa0633f8c5 fix(deps): update module k8s.io/client-go to v0.20.5 (#508)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-03-22 13:02:02 +09:00
Hidetake Iwata
74c9404e69 Fix multi-platform images (#514) 2021-03-22 12:10:22 +09:00
Hidetake Iwata
037d26b01f Publish multi-platform image to GHCR (#513) 2021-03-22 10:53:50 +09:00
Hidetake Iwata
256ce07e1f Migrate to krew-release-bot (#512) 2021-03-22 09:31:33 +09:00
Hidetake Iwata
23e85f8689 Migrate release to GitHub Actions (#511) 2021-03-21 22:36:25 +09:00
renovate[bot]
eb9a4121fb fix(deps): update golang.org/x/net commit hash to d523dce (#504)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-03-21 11:10:44 +00:00
renovate[bot]
7e24925248 fix(deps): update module k8s.io/apimachinery to v0.20.5 (#507)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-03-21 09:52:28 +00:00
renovate[bot]
b4f0f7feef fix(deps): update module github.com/chromedp/chromedp to v0.6.9 (#510)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-03-21 05:30:37 +00:00
renovate[bot]
fdff33f3df fix(deps): update golang.org/x/term commit hash to de623e6 (#506)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-03-17 17:40:54 +00:00
renovate[bot]
64294b9fa0 fix(deps): update golang.org/x/net commit hash to 34ac3e1 (#503)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-03-15 20:08:27 +00:00
Hidetake Iwata
9dcfb3a42c Migrate go test to GitHub Actions (#502) 2021-03-15 22:20:16 +09:00
Hidetake Iwata
644a7b0120 Fix trigger of system-test workflow (#501) 2021-03-15 19:28:10 +09:00
Hidetake Iwata
5f07f72889 Update get-token flags (#500) 2021-03-15 19:27:35 +09:00
Hidetake Iwata
d8af534b0b Update to Go 1.16 in system-test (#499) 2021-03-15 19:11:32 +09:00
Hidetake Iwata
eb7ce56909 Expand homedir paths in get-token options (#498)
* Expand homedir paths in get-token options

* Replace go-homedir with Go 1.16 os.UserHomeDir()
2021-03-15 19:03:11 +09:00
Mattias Appelgren
97cc85d079 repository: Expand ~ in homedir (#489)
Fixes: https://github.com/int128/kubelogin/issues/488
2021-03-14 09:07:29 +09:00
renovate[bot]
f849094c58 Update golang.org/x/oauth2 commit hash to cd4f82c (#496)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-03-13 20:03:37 +00:00
renovate[bot]
ebdda69c29 Update module k8s.io/klog/v2 to v2.8.0 (#495)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-03-13 03:56:56 +00:00
renovate[bot]
4d59503ebc Update cimg/go Docker tag to v1.16.2 (#494)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-03-13 01:02:56 +00:00
renovate[bot]
1a0e6ca973 Update module k8s.io/klog/v2 to v2.7.0 (#492)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-03-12 04:27:02 +00:00
renovate[bot]
c0d389588b Update golang.org/x/oauth2 commit hash to 5366d9d (#491)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-03-11 18:33:43 +00:00
renovate[bot]
ca9d3fad89 Update module github.com/chromedp/chromedp to v0.6.8 (#490)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-03-06 03:25:51 +00:00
renovate[bot]
6a6548c79a Update module github.com/google/go-cmp to v0.5.5 (#487)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-03-04 19:02:07 +00:00
renovate[bot]
bcaea01da7 Update module k8s.io/klog/v2 to v2.6.0 (#486)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-03-03 13:52:19 +00:00
renovate[bot]
3bf92a9ac1 Update golang.org/x/net commit hash to e18ecbb (#485)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-26 20:12:10 +00:00
renovate[bot]
78ece2f513 Update golang.org/x/net commit hash to 39120d0 (#484)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-26 13:40:01 +00:00
renovate[bot]
a9bf7a019a Update golang.org/x/net commit hash to 3d97a24 (#483)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-24 10:29:16 +00:00
renovate[bot]
03da20fe4d Update golang.org/x/net commit hash to 9060382 (#482)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-22 22:27:26 +00:00
renovate[bot]
1150aa45f8 Update module github.com/chromedp/chromedp to v0.6.6 (#481)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-22 09:53:39 +00:00
renovate[bot]
2513c3ce2c Update module github.com/golang/mock to v1.5.0 (#480)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-20 09:53:52 +00:00
renovate[bot]
f2e0a79817 Update golang.org/x/term commit hash to 6a3ed07 (#478)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-20 08:46:56 +00:00
renovate[bot]
3a59aad12a Update golang.org/x/sync commit hash to 036812b (#479)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-20 07:22:51 +00:00
renovate[bot]
21a5729719 Update golang.org/x/net commit hash to 5f55cee (#477)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-20 05:13:53 +00:00
renovate[bot]
60ae1f9d4b Update golang.org/x/oauth2 commit hash to 9bb9049 (#475)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-20 03:34:53 +00:00
renovate[bot]
b9f0f4b5b0 Update module k8s.io/client-go to v0.20.4 (#474)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-19 07:16:37 +00:00
renovate[bot]
5d0cbfeee5 Update module k8s.io/apimachinery to v0.20.4 (#473)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-19 03:51:33 +00:00
renovate[bot]
5818363cfd Update golang.org/x/oauth2 commit hash to ba52d33 (#472)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-18 23:11:11 +00:00
renovate[bot]
3cc4811a8c Update module k8s.io/client-go to v0.20.3 (#471)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-18 05:43:27 +00:00
renovate[bot]
a0c798ebfe Update module k8s.io/apimachinery to v0.20.3 (#470)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-18 03:38:31 +00:00
renovate[bot]
4e0d73e7b2 Update golang.org/x/oauth2 commit hash to 16ff188 (#469)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-16 21:42:37 +00:00
Hidetake Iwata
86681b82c5 Refactor homebrew formula (#468) 2021-02-11 20:27:52 +09:00
Hidetake Iwata
cc231f7f81 Create question.md 2021-02-11 17:55:57 +09:00
renovate[bot]
44ffd69cbf Update module coreos/go-oidc to v3 (#463)
* Update module coreos/go-oidc to v3

* Update import path to github.com/coreos/go-oidc/v3/oidc

Co-authored-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: Hidetake Iwata <int128@gmail.com>
2021-02-11 17:23:22 +09:00
Hidetake Iwata
c3f636300e Update to golangci-lint v1.36.0 (#460)
* Update golangci-lint.yaml

* Use golang.org/x/term

SA1019: package golang.org/x/crypto/ssh/terminal is deprecated: this package moved to golang.org/x/term.  (staticcheck)

* Add workflow name
2021-02-11 17:14:32 +09:00
renovate[bot]
f1a2539262 Update module spf13/cobra to v1.1.3 (#466)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-10 22:00:51 +00:00
renovate[bot]
5e7cb2aff1 Update golang.org/x/oauth2 commit hash to 6667018 (#465)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-10 21:23:31 +00:00
renovate[bot]
e47054ccdb Update module spf13/cobra to v1.1.2 (#464)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-10 03:26:03 +00:00
renovate[bot]
51d5af57cc Update cimg/go Docker tag to v1.15.8 (#462)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-05 00:42:53 +00:00
renovate[bot]
f29ea3a1c7 Update golang.org/x/oauth2 commit hash to 0101308 (#461)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-02-01 18:00:27 +00:00
renovate[bot]
1bb8fb2dc9 Update module k8s.io/klog/v2 to v2.5.0 (#459)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-27 19:33:47 +00:00
renovate[bot]
3e5c3e5918 Update golang.org/x/oauth2 commit hash to f9ce19e (#458)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-26 20:48:53 +00:00
renovate[bot]
cf85625b56 Update module google/wire to v0.5.0 (#457)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-26 03:37:13 +00:00
renovate[bot]
6987910fe6 Update golang.org/x/oauth2 commit hash to af13f52 (#456)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-25 21:04:32 +00:00
renovate[bot]
d89c2dc961 Update module coreos/go-oidc to v3 (#442)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-23 15:19:17 +09:00
renovate[bot]
4e2a99ba8e Update module chromedp/chromedp to v0.6.5 (#455)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-22 14:56:36 +00:00
renovate[bot]
3e915d0811 Update cimg/go Docker tag to v1.15.7 (#454)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-20 17:15:53 +00:00
renovate[bot]
1ca272f61a Update golang.org/x/net commit hash to 5f4716e (#453)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-19 21:31:20 +00:00
renovate[bot]
5b1cc1c994 Update module chromedp/chromedp to v0.6.4 (#452)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-17 02:49:01 +00:00
renovate[bot]
fa416f2910 Update github.com/pkg/browser commit hash to ce105d0 (#450)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-15 05:13:23 +00:00
renovate[bot]
ad65baa624 Update alpine Docker tag to v3.13 (#449)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-15 03:19:59 +00:00
renovate[bot]
25b8d29a44 Update module k8s.io/client-go to v0.20.2 (#448)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-14 03:06:18 +00:00
renovate[bot]
92b09e3e6f Update module k8s.io/apimachinery to v0.20.2 (#447)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-14 00:44:36 +00:00
renovate[bot]
10f904adbb Update golang.org/x/oauth2 commit hash to d3ed898 (#446)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-13 22:33:17 +00:00
renovate[bot]
55d2498dae Update golang.org/x/oauth2 commit hash to 8b1d76f (#445)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-13 17:31:48 +00:00
renovate[bot]
eaf5658d45 Update module chromedp/chromedp to v0.6.1 (#444)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-13 06:34:34 +00:00
renovate[bot]
5608c76764 Update golang.org/x/oauth2 commit hash to 01de73c (#443)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-12 21:18:59 +00:00
Hidetake Iwata
4915ce165f Delete CODEOWNERS 2021-01-11 11:55:00 +09:00
renovate[bot]
bd186d6cfc Update golang.org/x/sync commit hash to 09787c9 (#390)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-10 18:45:47 +00:00
renovate[bot]
411b42b6af Update golang.org/x/oauth2 commit hash to 08078c5 (#415)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-10 17:28:10 +00:00
renovate[bot]
671ee8ecf1 Update golang.org/x/net commit hash to 6772e93 (#407)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-10 16:36:05 +00:00
renovate[bot]
e5b179dfec Update golang.org/x/crypto commit hash to eec23a3 (#391)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-10 15:42:21 +00:00
renovate[bot]
435cdf4a78 Update github.com/pkg/browser commit hash to 0426ae3 (#416)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-10 14:12:42 +00:00
Hidetake Iwata
f94ff640d6 Update renovate.json 2021-01-10 22:49:33 +09:00
renovate[bot]
9be8740f45 Update cimg/go Docker tag to v1.15.6 (#434)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-10 13:16:22 +00:00
Hidetake Iwata
637d091b40 Enable renovate-approve 2021-01-10 21:36:03 +09:00
Hidetake Iwata
637fc746fd Enable automerge 2021-01-10 21:32:24 +09:00
renovate[bot]
7e063b5dda Update module yaml to v2.4.0 (#433)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-10 17:45:49 +09:00
renovate[bot]
202a8616c6 Update module chromedp/chromedp to v0.6.0 (#435)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-09 21:44:56 +09:00
renovate[bot]
21b88cf037 Update module k8s.io/klog/v2 to v2.4.0 (#441)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-01-09 20:17:26 +09:00
Yuri V
38772898fc Switch klog to v2 (#439)
Co-authored-by: Hidetake Iwata <int128@gmail.com>
2021-01-09 18:51:04 +09:00
Hidetake Iwata
58d1839f3e Create CODEOWNERS 2021-01-09 18:13:47 +09:00
renovate[bot]
c7606e8151 Update module google/go-cmp to v0.5.4 (#432)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-12-19 22:26:34 +09:00
renovate[bot]
eb0f2009e2 Update module k8s.io/client-go to v0.20.1 (#438)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-12-19 21:14:06 +09:00
Hidetake Iwata
cffb00f386 Refactor: extract tests into authentication_test.go (#431) 2020-11-23 18:20:47 +09:00
Hidetake Iwata
8e1a63b1a2 Change mutex scope to bind address port (#430) 2020-11-23 17:41:07 +09:00
Hidetake Iwata
ebf81debe1 Refactor: credentialplugin/get_token_test.go (#429)
* Refactor: extract const vars

* Refactor: extract ROPC test case
2020-11-22 20:01:45 +09:00
Hidetake Iwata
2f271b5870 Refactor: replace Input fields with oidc.Provider (#428) 2020-11-21 12:35:23 +09:00
Hidetake Iwata
b1d8e8f7e1 Refactor: rewrite with Go errors package (#427) 2020-11-21 12:10:42 +09:00
Hidetake Iwata
5a3227409c Refactor: rename to infrastructure package (#426) 2020-11-21 07:56:52 +09:00
Hidetake Iwata
13d232ec21 Refactor: move oidc/client package (#425) 2020-11-21 07:27:34 +09:00
Hidetake Iwata
9bab6b2ccd Refactor: extract tokencache and repository package (#424) 2020-11-20 07:01:16 +09:00
Hidetake Iwata
93fc548544 Refactor: extract kubeconfig package (#423)
* Refactor: extract kubeconfig package

* Refactor: use pass by value instead of reference
2020-11-18 10:36:42 +09:00
Hidetake Iwata
4773b67abd Refactor: extract credentialplugin package (#422) 2020-11-18 10:00:39 +09:00
renovate[bot]
009d03cb69 Update module google/go-cmp to v0.5.3 (#417)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-11-14 21:24:05 +09:00
renovate[bot]
417c556e8f Update module k8s.io/client-go to v0.19.4 (#420)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-11-14 20:51:43 +09:00
renovate[bot]
2542d6456c Update cimg/go Docker tag to v1.15.5 (#418)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-11-14 17:54:11 +09:00
renovate[bot]
e3af16ca8f Update cimg/go Docker tag to v1.15.4 (#410)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-11-10 21:30:26 +09:00
Hidetake Iwata
8926e8940a Fix TLS error if CA certificate is not set (#412) 2020-11-08 15:56:41 +09:00
Hidetake Iwata
ce7784b8a0 Add TLS renegotiation flags (#411) 2020-11-07 13:08:29 +09:00
Hidetake Iwata
34762216c1 Refactor: extract tlsclientconfig.Config (#409) 2020-11-03 14:37:24 +09:00
Eric Poitras
878847f937 feat(389): Prevent concurrent authentication using a lockfile. (#397)
* feat(389): Prevent concurrent authentication using a lockfile to protect the local port allocation.

* Fix test

* Refactor: inline values

Co-authored-by: Hidetake Iwata <int128@gmail.com>
2020-10-25 14:32:53 +09:00
Hidetake Iwata
8a392ba25a Refactor: use gotestsum for CircleCI (#377) 2020-10-25 12:47:32 +09:00
Hidetake Iwata
b701a6f0aa Refactor: aggregate test cases to lease and full options (#406) 2020-10-25 12:24:35 +09:00
Hidetake Iwata
10091a3238 go mod tidy 2020-10-25 11:35:58 +09:00
Christoph Stäbler
d1b89e3d38 Add username in token cache key (#404) 2020-10-24 20:44:29 +09:00
renovate[bot]
e862ac7eac Update module spf13/cobra to v1.1.1 (#400)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-10-24 09:26:08 +09:00
renovate[bot]
d051d80435 Update module k8s.io/client-go to v0.19.3 (#403)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-10-24 09:25:29 +09:00
Hidetake Iwata
14e58ac4c2 Update README.md 2020-10-18 08:51:09 +09:00
renovate[bot]
748eb12fc0 Update module spf13/cobra to v1.1.0 (#398)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: Hidetake Iwata <int128@gmail.com>
2020-10-18 08:43:36 +09:00
renovate[bot]
8b232eeb3e Update cimg/go Docker tag to v1.15.3 (#399)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-10-18 08:37:40 +09:00
Hidetake Iwata
0694a1cd0b Update system-test.yaml 2020-10-18 08:37:17 +09:00
Hidetake Iwata
9ddeb33d27 Update golangci-lint.yaml 2020-10-18 08:35:13 +09:00
Hidetake Iwata
64bfc5a465 Refactor authentication use-cases (#395) 2020-10-03 20:01:26 +09:00
Hidetake Iwata
5b2c82fc33 Refactor: replace DTO with oidc.TokenSet type (#394)
* Refactor: remove IDTokenClaims from TokenSet and decode in use-cases

* Refactor: use oidc.TokenSet for cache repository
2020-10-03 17:49:21 +09:00
Hidetake Iwata
1dee4a354e Refactor: extract oidc.Provider (#393) 2020-10-03 08:35:35 +09:00
Hidetake Iwata
336f2b83d5 go mod tidy 2020-10-03 08:06:47 +09:00
Hidetake Iwata
6071dd83a3 Update feature_request.md 2020-09-28 09:38:53 +09:00
Hidetake Iwata
784378cbe6 Update bug_report.md 2020-09-28 09:36:42 +09:00
renovate[bot]
fe54383df9 Update module k8s.io/client-go to v0.19.2 (#380)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-09-28 09:29:26 +09:00
Hidetake Iwata
257c05dbf3 Change authentication timeout to 180 sec (#388) 2020-09-28 09:28:44 +09:00
Hidetake Iwata
e543a7bbe0 Update usage.md 2020-09-27 22:04:31 +09:00
Hidetake Iwata
ebdfcfb1c8 Add --authentication-timeout-sec flag (#387) 2020-09-27 21:55:55 +09:00
Hidetake Iwata
7bc76a5e79 Refactor: system test (#386) 2020-09-26 16:36:05 +09:00
Hidetake Iwata
ed0a5318ec Fix system test for kind v0.9.0 (#385) 2020-09-26 12:19:34 +09:00
Hidetake Iwata
881786a820 Add integration test for HTTPS local server (#383) 2020-09-25 10:14:17 +09:00
Hidetake Iwata
5ab2f9e01e Refactor: replace temporary dirs with t.TempDir() (#382) 2020-09-25 10:10:11 +09:00
TJ Miller
56169d1673 Add support for HTTPS redirect URI (#381)
* Add local server certificate option

* fix trailing slash from step 5 kubectl config set-credentials

* Add local https documentation

* Change flags to --local-server-cert and --local-server-key

* Add tests for flags

Co-authored-by: TJ Miller <millert@us.ibm.com>
Co-authored-by: Hidetake Iwata <int128@gmail.com>
2020-09-25 09:44:00 +09:00
renovate[bot]
592f2722fd Update cimg/go Docker tag to v1.15.2 (#373)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-09-11 21:03:11 +09:00
renovate[bot]
2e450b6f79 Update golang.org/x/oauth2 commit hash to 5d25da1 (#376)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-09-05 15:28:03 +09:00
renovate[bot]
ec38934b7e Update golang.org/x/crypto commit hash to 5c72a88 (#328)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-09-03 06:54:16 +09:00
Hidetake Iwata
9dfeb2f735 go mod tidy 2020-09-03 06:45:35 +09:00
Hidetake Iwata
c051d4e51a Refactor: close channel in writer goroutine (#375) 2020-09-03 06:44:46 +09:00
Hidetake Iwata
88f03655ea Add Chocolatey installation (#374) 2020-09-02 12:05:56 +09:00
renovate[bot]
fae53fd634 Update module k8s.io/client-go to v0.19.0 (#369)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-09-02 11:16:33 +09:00
renovate[bot]
43f1c44ea4 Update module int128/oauth2cli to v1.13.0 (#372)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-09-01 22:25:40 +09:00
renovate[bot]
23cbc28649 Update module k8s.io/client-go to v0.18.8 (#356)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-08-16 16:26:11 +09:00
Hidetake Iwata
003cb6c77c Bump the version of golangci-lint-action to v2 (#364) 2020-08-16 16:25:36 +09:00
Hidetake Iwata
c039323693 Add golangci-lint workflow (#363) 2020-08-16 16:10:16 +09:00
Hidetake Iwata
5f0e1750bd Run system test when go.mod/sum is changed (#360) 2020-08-15 00:27:21 +09:00
Hidetake Iwata
e0e3287feb Bump the version of golangci-lint to v1.30.0 (#359) 2020-08-15 00:23:12 +09:00
renovate[bot]
6dad6b3751 Update cimg/go Docker tag to v1.14.7 (#353)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-08-14 23:46:14 +09:00
Hidetake Iwata
c095bdabc1 Refactor GitHub actions workflow (#358)
* Use preinstalled kind

* Use the latest Go

* Bump the version of actions

* Run system test only if related source is changed
2020-08-14 23:36:11 +09:00
Hidetake Iwata
daf563ea9a Refactor: extract usage.md from README.md (#357)
* Refactor docs

* Update usage.md
2020-08-14 23:22:38 +09:00
renovate[bot]
cf73e9a495 Update cimg/go Docker tag to v1.14.6 (#340)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-08-02 14:29:59 +09:00
Hidetake Iwata
488e8c62ec Determine go version from .circleci/config.yml (#351) 2020-08-02 12:08:26 +09:00
Hidetake Iwata
58d170fa65 Add --open-url-after-authentication option (#350)
* Add --open-url-after-authentication option

* Add integration test for --open-url-after-authentication
2020-08-01 10:38:33 +09:00
Hidetake Iwata
c488888834 Refactor: pull up packages of domain (#349) 2020-07-30 09:37:10 +09:00
Hidetake Iwata
2cd741735e Refactor: move templates.AuthCodeBrowserSuccessHTML to authcode (#348) 2020-07-30 09:29:49 +09:00
Hidetake Iwata
dbb684f10e Refactor: use oidc.TokenSet in adaptors (#347) 2020-07-30 09:26:21 +09:00
Hidetake Iwata
a0e81e762c Refactor: split authentication package into methods (#346) 2020-07-30 00:31:23 +09:00
Hidetake Iwata
c4ce1629e2 Refactor: regenerate with the latest mockgen (#345) 2020-07-30 00:04:56 +09:00
renovate[bot]
e965114ecb Update module golang/mock to v1.4.4 (#344)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-07-29 23:54:50 +09:00
Hidetake Iwata
804a245fde Refactor: rename to AuthCodeBrowser (#342) 2020-07-26 18:49:22 +09:00
Hidetake Iwata
ffaa26cba8 Merge pull request #341 from int128/refactor-flags
Refactor flags
2020-07-26 18:18:45 +09:00
Hidetake Iwata
923a4251f1 Change messages in standalone mode 2020-07-26 18:11:39 +09:00
Hidetake Iwata
98b84d87e0 Refactor: change options description 2020-07-26 15:39:09 +09:00
Hidetake Iwata
1ae2008e28 Refactor: extract tlsOptions 2020-07-26 15:39:09 +09:00
Hidetake Iwata
8197b5b35a Refactor: extract authentication.go 2020-07-26 12:00:15 +09:00
Hidetake Iwata
7196c64bec Refactor: rename to addFlags() 2020-07-26 12:00:15 +09:00
Hidetake Iwata
d8419f0dd3 go mod tidy 2020-07-26 11:59:57 +09:00
renovate[bot]
5f61d298f5 Update alpine Docker tag to v3.12 (#330)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-07-24 17:02:07 +09:00
renovate[bot]
7310b3c271 Update golang.org/x/sync commit hash to 6e8e738 (#329)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-07-24 16:40:22 +09:00
Hidetake Iwata
ba4d010f86 Enable go mod tidy on Renovate (#339) 2020-07-24 15:00:50 +09:00
Hidetake Iwata
41d8e74ba9 Reduce time of CircleCI macOS executor (#338) 2020-07-23 17:37:55 +09:00
renovate[bot]
23a1efb4f1 Update module k8s.io/client-go to v0.18.6 (#333)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-07-23 08:29:03 +09:00
renovate[bot]
3cfeacc861 Update module google/go-cmp to v0.5.1 (#337)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-07-22 14:59:49 +09:00
renovate[bot]
509f29637b Add renovate.json (#322)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2020-07-21 10:33:31 +09:00
Hidetake Iwata
4f96435e97 Show debug logs in authentication (#325) 2020-07-14 09:50:02 +09:00
Hidetake Iwata
22005fb715 go mod tidy 2020-07-14 09:14:51 +09:00
dependabot-preview[bot]
8af36b13e4 Build(deps): bump github.com/int128/oauth2cli from 1.11.0 to 1.12.1 (#324)
Bumps [github.com/int128/oauth2cli](https://github.com/int128/oauth2cli) from 1.11.0 to 1.12.1.
- [Release notes](https://github.com/int128/oauth2cli/releases)
- [Commits](https://github.com/int128/oauth2cli/compare/v1.11.0...v1.12.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-07-14 07:06:48 +09:00
Hidetake Iwata
f0c399b8fc go mod tidy 2020-07-05 19:50:26 +09:00
dependabot-preview[bot]
17499aac24 Build(deps): bump k8s.io/client-go from 0.18.4 to 0.18.5 (#320)
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.18.4 to 0.18.5.
- [Release notes](https://github.com/kubernetes/client-go/releases)
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.18.4...v0.18.5)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-07-03 09:08:57 +09:00
Hidetake Iwata
d81457995d Add links to use Okta groups claim (#318)
This will close #250.
2020-06-24 10:18:54 +09:00
Hidetake Iwata
2e7b93a31e Add issue templates (#317) 2020-06-24 09:28:52 +09:00
Hidetake Iwata
9aeffbc71e Update README.md 2020-06-24 01:10:25 +09:00
Hidetake Iwata
c2b0c101af Change margin of success page (#316) 2020-06-24 00:53:51 +09:00
Hidetake Iwata
e8161d5a47 go mod tidy 2020-06-23 16:27:05 +09:00
dependabot-preview[bot]
a3946c7f5f Build(deps): bump k8s.io/client-go from 0.18.3 to 0.18.4 (#309)
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.18.3 to 0.18.4.
- [Release notes](https://github.com/kubernetes/client-go/releases)
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.18.3...v0.18.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-06-23 16:24:41 +09:00
dependabot-preview[bot]
6b880febdb Build(deps): bump k8s.io/apimachinery from 0.18.3 to 0.18.4 (#310)
Bumps [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) from 0.18.3 to 0.18.4.
- [Release notes](https://github.com/kubernetes/apimachinery/releases)
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.18.3...v0.18.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-06-23 15:03:51 +09:00
dependabot-preview[bot]
a51c15aec2 Build(deps): bump github.com/google/go-cmp from 0.4.1 to 0.5.0 (#311)
Bumps [github.com/google/go-cmp](https://github.com/google/go-cmp) from 0.4.1 to 0.5.0.
- [Release notes](https://github.com/google/go-cmp/releases)
- [Commits](https://github.com/google/go-cmp/compare/v0.4.1...v0.5.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-06-23 15:01:28 +09:00
Hidetake Iwata
77a6b91be8 Change authentication success page more descriptive (#312)
* Refactor: rename to authcode_browser.go

* Change authentication success page more descriptive
2020-06-23 15:00:58 +09:00
Hidetake Iwata
9e27385c0b Add acceptance test (#315) 2020-06-23 14:47:29 +09:00
Hidetake Iwata
3c50431a09 Refactor: rename to system test (#314) 2020-06-22 16:22:03 +09:00
Hidetake Iwata
e41fdf3dcd Fix error of acceptance test (#313) 2020-06-22 14:33:54 +09:00
Hidetake Iwata
dd93a6537d Update README.md 2020-06-14 16:19:52 +09:00
Hidetake Iwata
822f6c86de Remove redundant information from caveats (#306)
This reflects the change of https://github.com/kubernetes-sigs/krew-index/pull/635
2020-06-12 18:20:01 +09:00
Hidetake Iwata
dd22ccb9c3 Bump version of github.com/spf13/cobra to v1.0.0 (#305) 2020-06-12 14:46:59 +09:00
Hidetake Iwata
f6c4a1257d Update acceptance-test.yaml 2020-06-12 14:35:59 +09:00
Hidetake Iwata
a0c62a9ff1 Move to CircleCI macOS build (#304) 2020-06-12 14:28:32 +09:00
Andreas Lindhé
0aa3e43e62 Remove install instructions for Github releases (#303)
* Remove install instructions for Github releases

Fixes #301

* Update README.md

Co-authored-by: Hidetake Iwata <int128@gmail.com>
2020-06-10 10:37:26 +09:00
Hidetake Iwata
9028199abb Bump kind version to v0.8.1 (#300) 2020-06-09 16:22:42 +09:00
ThomasAlxDmy
c308ccb511 CGO_ENABLE as a make option (#299)
* CGO_ENABLE as a make option

* Update Makefile

* Update Makefile

Co-authored-by: Thomas Dmytryk <tdmytryk@tesla.com>
Co-authored-by: Hidetake Iwata <int128@gmail.com>
2020-05-28 00:50:29 +09:00
Hidetake Iwata
ff1aa97d87 go mod tidy 2020-05-23 00:48:37 +09:00
dependabot-preview[bot]
ca21c6568b Build(deps): bump k8s.io/client-go from 0.18.2 to 0.18.3 (#296)
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.18.2 to 0.18.3.
- [Release notes](https://github.com/kubernetes/client-go/releases)
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.18.2...v0.18.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-05-23 00:48:06 +09:00
dependabot-preview[bot]
117a8d35d4 Build(deps): bump github.com/google/go-cmp from 0.4.0 to 0.4.1 (#294)
Bumps [github.com/google/go-cmp](https://github.com/google/go-cmp) from 0.4.0 to 0.4.1.
- [Release notes](https://github.com/google/go-cmp/releases)
- [Commits](https://github.com/google/go-cmp/compare/v0.4.0...v0.4.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-05-22 21:51:49 +09:00
Hidetake Iwata
5557290105 Bump the version to v1.19.1 2020-05-16 18:25:10 +09:00
Hidetake Iwata
fe85419312 go mod tidy 2020-05-16 18:07:23 +09:00
dependabot-preview[bot]
d8d810bc0d Build(deps): bump k8s.io/client-go from 0.18.1 to 0.18.2 (#277)
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.18.1 to 0.18.2.
- [Release notes](https://github.com/kubernetes/client-go/releases)
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.18.1...v0.18.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-05-16 17:49:11 +09:00
dependabot-preview[bot]
170eeb4ed5 Build(deps): bump gopkg.in/yaml.v2 from 2.2.8 to 2.3.0 (#288)
Bumps [gopkg.in/yaml.v2](https://github.com/go-yaml/yaml) from 2.2.8 to 2.3.0.
- [Release notes](https://github.com/go-yaml/yaml/releases)
- [Commits](https://github.com/go-yaml/yaml/compare/v2.2.8...v2.3.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-05-16 16:50:25 +09:00
Michael Goodwin
01637fbe12 Update brew template to include support for LinuxBrew (#291)
This commit introduces an OS check, and extra variables `baseurl` and `kernel` to determine the right archive to download based on the platform. `baseurl` is used to compose the full URI with `#{version}` and `#{kernel}` ruby variables
2020-05-16 16:28:33 +09:00
Hidetake Iwata
e152e95a9f Refactor: add integration test of PKCE (#293)
* Refactor: add integration test of PKCE

* Refactor: fix name to pkce/Params.IsZero()
2020-05-16 14:29:42 +09:00
Hidetake Iwata
bf8eefd045 Refactor: reduce test cases of integration test (#292) 2020-05-14 16:49:39 +09:00
Hidetake Iwata
e88138c640 Refactor: fix token verifier does not respect clock (#290) 2020-05-13 15:45:14 +09:00
Hidetake Iwata
9ad520ba22 Refactor: inject stdout mock in integration test (#289) 2020-05-13 11:25:59 +09:00
Hidetake Iwata
35e8ecab8d Refactor: replace newCredentialPluginWriterMock (#287)
* Refactor: replace newCredentialPluginWriterMock

* Refactor: remove unused mock and files
2020-05-12 14:36:13 +09:00
Hidetake Iwata
c5621239e8 Refactor: remove unused mock and files 2020-05-12 14:17:19 +09:00
Hidetake Iwata
582ca48092 Refactor: replace newCredentialPluginWriterMock 2020-05-12 14:17:18 +09:00
Hidetake Iwata
da32d2184d Refactor: remove Server.NewTokenResponse() (#286) 2020-05-11 20:41:46 +09:00
Hidetake Iwata
3a9768d6de Refactor: extract httpdriver package (#285) 2020-05-11 12:06:11 +09:00
Hidetake Iwata
16d6fa2fbb Refactor: replace idp mock with oidcserver package (#284) 2020-05-11 11:51:21 +09:00
Hidetake Iwata
175275bf3d Fix to send challenge only if provider supports PKCE (#283) 2020-05-08 22:19:32 +09:00
Hidetake Iwata
4ffc914d0e Bump the version 2020-04-11 17:14:59 +09:00
Hidetake Iwata
fa008bef55 Add linux_arm and linux_arm64 binary to distribution (#275) 2020-04-11 17:14:00 +09:00
Hidetake Iwata
50047417ab Delete snapcraft.yaml 2020-04-11 16:10:48 +09:00
Hidetake Iwata
4c0ebb0284 go mod tidy 2020-04-11 15:57:57 +09:00
dependabot-preview[bot]
c1173accd3 Build(deps): bump k8s.io/client-go from 0.18.0 to 0.18.1 (#273)
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.18.0 to 0.18.1.
- [Release notes](https://github.com/kubernetes/client-go/releases)
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.18.0...v0.18.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-04-11 15:57:17 +09:00
Hidetake Iwata
d4addcfc6e Show Go version, GOOS and GOARCH in version command (#272) 2020-04-11 11:39:49 +09:00
Hidetake Iwata
695347e419 Merge pull request #271 from int128/refactor
Refactor integration test
2020-04-10 20:39:18 +09:00
Hidetake Iwata
d5c738697f Refactor: tidy up 2020-04-10 20:32:22 +09:00
Hidetake Iwata
777a60c96c Refactor: rename package 2020-04-10 17:15:02 +09:00
Hidetake Iwata
6f6e0723f1 Refactor: extract integration_test.authCodeFlowConfig 2020-04-10 16:32:02 +09:00
Hidetake Iwata
3fb074a4a8 Refactor: replace ClusterRoleBinding manifest with kubectl command (#270) 2020-04-08 20:38:35 +09:00
Hidetake Iwata
59b5f1bd89 Add --oidc-redirect-url-hostname flag (#269) 2020-04-08 15:25:19 +09:00
Hidetake Iwata
70819843f0 go mod tidy 2020-04-07 10:30:13 +09:00
dependabot-preview[bot]
87c46a24ae Build(deps): bump github.com/int128/oauth2cli from 1.10.0 to 1.11.0 (#268)
Bumps [github.com/int128/oauth2cli](https://github.com/int128/oauth2cli) from 1.10.0 to 1.11.0.
- [Release notes](https://github.com/int128/oauth2cli/releases)
- [Commits](https://github.com/int128/oauth2cli/compare/v1.10.0...v1.11.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-04-07 10:27:30 +09:00
Hidetake Iwata
ac504150b2 Bump k8s.io/apimachinery, k8s.io/client-go to 0.18.0 (#267) 2020-04-06 21:58:53 +09:00
Hidetake Iwata
caeb55f21d Refactor: enable Go module cache (#264) 2020-04-02 20:08:52 +09:00
dependabot-preview[bot]
2ccda6099f Build(deps): bump github.com/spf13/cobra from 0.0.6 to 0.0.7 (#263)
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 0.0.6 to 0.0.7.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v0.0.6...0.0.7)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-31 11:34:19 +09:00
MOZGIII
7f4f72c9e0 Correct the command args at stage 2 instructions (#261) 2020-03-29 18:26:29 +09:00
Hidetake Iwata
bfc1568057 Bump the version 2020-03-26 10:36:06 +09:00
Hidetake Iwata
8758d55bb3 go mod tidy 2020-03-26 10:29:32 +09:00
dependabot-preview[bot]
d9be392f5a Build(deps): bump k8s.io/client-go from 0.17.3 to 0.17.4 (#252)
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.17.3 to 0.17.4.
- [Release notes](https://github.com/kubernetes/client-go/releases)
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.17.3...v0.17.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-26 10:24:49 +09:00
dependabot-preview[bot]
af840a519c Build(deps): bump github.com/golang/mock from 1.4.0 to 1.4.3 (#253)
Bumps [github.com/golang/mock](https://github.com/golang/mock) from 1.4.0 to 1.4.3.
- [Release notes](https://github.com/golang/mock/releases)
- [Changelog](https://github.com/golang/mock/blob/master/.goreleaser.yml)
- [Commits](https://github.com/golang/mock/compare/v1.4.0...v1.4.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-26 10:24:31 +09:00
Hidetake Iwata
285b3b15a8 Bump to Go 1.14.1 (#258) 2020-03-26 10:13:54 +09:00
Matthew M. Boedicker
123d7c8124 Add --oidc-extra-url-params argument (#255)
* Add --oidc-extra-url-params argument

This accepts a comma-separated list of key-value pairs that will be
added to get token requests as query string parameters.

Closes #254.

* Refactor

- move code setting the extra params to the authorization code flow specific functions (it is not needed in ROPC flow)
- add unit tests
- rename flag to --oidc-auth-request-extra-params
- add description to README.md

* Add integration test for --oidc-auth-request-extra-params

Co-authored-by: Hidetake Iwata <int128@gmail.com>
2020-03-25 11:52:53 +09:00
Hidetake Iwata
e2a6b5d4e2 Update README.md 2020-03-06 10:26:06 +09:00
dependabot-preview[bot]
ce93c739f8 Build(deps): bump github.com/int128/oauth2cli from 1.9.0 to 1.10.0 (#246)
Bumps [github.com/int128/oauth2cli](https://github.com/int128/oauth2cli) from 1.9.0 to 1.10.0.
- [Release notes](https://github.com/int128/oauth2cli/releases)
- [Commits](https://github.com/int128/oauth2cli/compare/v1.9.0...v1.10.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-28 22:08:48 +09:00
Hidetake Iwata
dc646c88f9 Bump version to v1.17.1 2020-02-22 16:04:29 +09:00
Hidetake Iwata
07e34d2222 Refactor (#245)
* Refactor: use Command.Context

* Refactor: do not infer command name for help/version
2020-02-22 15:40:43 +09:00
Hidetake Iwata
0e2d402c40 Bump github.com/int128/oauth2cli to v1.9.0 (#244)
* Bump github.com/int128/oauth2cli to v1.9.0

* Generate state parameter and pass to oauth2cli

* Refactor: use base64.NoPadding
2020-02-22 15:26:54 +09:00
Hidetake Iwata
db7c260f9d go mod tidy 2020-02-22 12:41:11 +09:00
dependabot-preview[bot]
a95dc5c794 Build(deps): bump github.com/spf13/cobra from 0.0.5 to 0.0.6 (#239)
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 0.0.5 to 0.0.6.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/0.0.5...v0.0.6)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-22 12:39:26 +09:00
dependabot-preview[bot]
846804f611 Build(deps): bump k8s.io/client-go from 0.17.2 to 0.17.3 (#236)
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.17.2 to 0.17.3.
- [Release notes](https://github.com/kubernetes/client-go/releases)
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.17.2...v0.17.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-22 12:32:56 +09:00
Hidetake Iwata
8b9e31b4c5 Refactor: error messages and testing/logger (#243)
* Refactor: respect -v option in testing/logger

* Refactor: revise error messages
2020-02-22 12:31:00 +09:00
Hidetake Iwata
bc99af6eab Merge pull request #242 from int128/refactor
Refactor
2020-02-21 23:37:32 +09:00
Hidetake Iwata
e3bec130f4 Refactor: fix mock package path 2020-02-21 22:59:59 +09:00
Hidetake Iwata
d59e3355fe Refactor: rename to adaptor/reader 2020-02-21 22:56:43 +09:00
Hidetake Iwata
9d2d0109d5 Refactor: extract adaptor/clock and testing/clock 2020-02-21 22:49:48 +09:00
Hidetake Iwata
aac8780caf Refactor: move to testing/logger 2020-02-21 22:39:27 +09:00
Hidetake Iwata
f89525b184 Refactor: extract domain/jwt and testing/jwt (#241)
* Refactor: extract domain/jwt and testing/jwt

* Refactor: remove jwt-go dep from product code
2020-02-21 22:33:08 +09:00
Hidetake Iwata
a46dab3dfd Fix error if multiple aud claim is given (#240) 2020-02-21 09:58:01 +09:00
Hidetake Iwata
42879dc915 Revise setup instruction (#235) 2020-02-12 21:27:08 +09:00
Hidetake Iwata
7ce98c7119 Add --certificate-authority-data option (#233) 2020-02-12 10:15:12 +09:00
dependabot-preview[bot]
8b5e87de75 Build(deps): bump github.com/coreos/go-oidc (#221)
Bumps [github.com/coreos/go-oidc](https://github.com/coreos/go-oidc) from 2.1.0+incompatible to 2.2.1+incompatible.
- [Release notes](https://github.com/coreos/go-oidc/releases)
- [Commits](https://github.com/coreos/go-oidc/compare/v2.1.0...v2.2.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-11 17:06:10 +09:00
Hidetake Iwata
1b545e1c58 Refactor: Use BROWSER env var to run chrome-login script (#232)
* Use BROWSER env var to run chrome-login script

* Update acceptance-test-diagram.svg

* Added acceptance-test-diagram.svg
2020-02-11 16:06:04 +09:00
Hidetake Iwata
2fa306c348 Improve error message if cannot open browser (#230) 2020-02-11 15:50:10 +09:00
Hidetake Iwata
9018cd65c5 Refactor: rename to integration_test (#228) 2020-02-07 20:58:13 +09:00
Hidetake Iwata
9fe6a09943 Fix flaky acceptance test (#229) 2020-02-07 20:45:51 +09:00
Hidetake Iwata
c53d415255 Refactor test and interfaces (#227)
* Refactor: extract adaptors.browser package

* Refactor: rename to idp.Provider

* Refactor: rename to adaptors.credentialpluginwriter
2020-02-07 11:56:31 +09:00
Hidetake Iwata
aa0718df16 Refactor: Makefile of e2e_test/keys/testdata (#226) 2020-02-06 10:44:55 +09:00
Hidetake Iwata
40698536b0 Delete Dockerfile
Fix up #224
2020-02-05 00:31:35 +09:00
Hidetake Iwata
7ec53a5dd1 Reduce time of acceptance test (#224)
* Reduce time of acceptance test

* Update README.md
2020-02-05 00:30:13 +09:00
Hidetake Iwata
3a28e44556 Add Docker usage (#223) 2020-02-02 10:55:47 +09:00
Hidetake Iwata
f8cca818af Add acceptance test (#222)
* Add acceptance test

* Update README.md

* Update README.md

* Added acceptance-test-diagram.svg

* Update README.md

* Add files via upload

* Added acceptance-test-diagram.svg

* Added acceptance-test-diagram.svg

* Update README.md

* Update README.md
2020-01-31 21:45:23 +09:00
Hidetake Iwata
0c6ca03eb9 Fix docker build error (#220)
upstream: https://github.com/int128/kubelogin-docker/pull/1
2020-01-24 11:14:11 +09:00
Hidetake Iwata
fe2fbcbc53 Refactor: use ghcp for release assets and PR (#219) 2020-01-24 10:59:08 +09:00
Hidetake Iwata
812a965739 go mod tidy 2020-01-24 10:51:45 +09:00
dependabot-preview[bot]
6de1fca64c Build(deps): bump gopkg.in/yaml.v2 from 2.2.7 to 2.2.8 (#217)
Bumps [gopkg.in/yaml.v2](https://github.com/go-yaml/yaml) from 2.2.7 to 2.2.8.
- [Release notes](https://github.com/go-yaml/yaml/releases)
- [Commits](https://github.com/go-yaml/yaml/compare/v2.2.7...v2.2.8)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-24 10:50:42 +09:00
Hidetake Iwata
0eb8cdc95f Add Dockerfile for release (#218) 2020-01-24 10:46:05 +09:00
dependabot-preview[bot]
995c0997d5 Build(deps): bump github.com/golang/mock from 1.3.1 to 1.4.0 (#215)
Bumps [github.com/golang/mock](https://github.com/golang/mock) from 1.3.1 to 1.4.0.
- [Release notes](https://github.com/golang/mock/releases)
- [Changelog](https://github.com/golang/mock/blob/master/.goreleaser.yml)
- [Commits](https://github.com/golang/mock/compare/1.3.1...v1.4.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-23 10:59:56 +09:00
dependabot-preview[bot]
18b2437819 Build(deps): bump k8s.io/client-go from 0.17.1 to 0.17.2 (#216)
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.17.1 to 0.17.2.
- [Release notes](https://github.com/kubernetes/client-go/releases)
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.17.1...v0.17.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-23 10:54:29 +09:00
dependabot-preview[bot]
5d5a33b8ea Build(deps): bump k8s.io/client-go from 0.17.0 to 0.17.1 (#212)
Bumps [k8s.io/client-go](https://github.com/kubernetes/client-go) from 0.17.0 to 0.17.1.
- [Release notes](https://github.com/kubernetes/client-go/releases)
- [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md)
- [Commits](https://github.com/kubernetes/client-go/compare/v0.17.0...v0.17.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-20 11:24:47 +09:00
Hidetake Iwata
a614943642 Bump version of k8s.io/client-go, k8s.io/apimachinery (#210) 2020-01-17 22:31:48 +09:00
Hidetake Iwata
d223175b92 Refactor dependency injection (#209)
* Refactor: use func type instead of factory interface

* Refactor: remove duplicated dependencies in di.go
2020-01-17 22:01:40 +09:00
Hidetake Iwata
6075c9dbe7 Add --listen-address option to bind all interfaces (#208) 2020-01-17 20:57:05 +09:00
Hidetake Iwata
be43c2ab82 Refactor: improve CI portability (#205) 2020-01-10 12:19:43 +09:00
Hidetake Iwata
512df0c4e4 go mod tidy 2020-01-09 15:56:20 +09:00
dependabot-preview[bot]
5d5292637f Build(deps): bump github.com/google/go-cmp from 0.3.1 to 0.4.0 (#204)
Bumps [github.com/google/go-cmp](https://github.com/google/go-cmp) from 0.3.1 to 0.4.0.
- [Release notes](https://github.com/google/go-cmp/releases)
- [Commits](https://github.com/google/go-cmp/compare/v0.3.1...v0.4.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-01-09 14:51:38 +09:00
Hidetake Iwata
76f61300d6 Refactor: extract oidc.Claims model (#202)
* Refactor: extract oidc.Claims model

* Refactor: extract Claims.IsExpired()
2019-12-26 20:17:30 +09:00
Hidetake Iwata
f7f1985a89 Refactor (#201)
* Refactor: rename to tokencache.Value

* Refactor: move to cmp.Diff from deep.Equal

* Refactor: reword error messages
2019-12-26 11:51:14 +09:00
Hidetake Iwata
3d47c88a8d Fix token cache is not refreshed when oidc options changed (#200) 2019-12-25 10:44:44 +09:00
201 changed files with 9870 additions and 5808 deletions

View File

@@ -1,40 +0,0 @@
version: 2
jobs:
build:
docker:
- image: circleci/golang:1.13.3
steps:
- run: |
sudo apt install -y file
- run: |
mkdir -p ~/bin
echo 'export PATH="$HOME/bin:$PATH"' >> $BASH_ENV
- run: |
curl -L -o ~/bin/ghcp https://github.com/int128/ghcp/releases/download/v1.5.0/ghcp_linux_amd64
chmod +x ~/bin/ghcp
- run: |
curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b ~/bin v1.21.0
- run: go get github.com/int128/goxzst
- run: go get github.com/tcnksm/ghr
- checkout
- run: make check
- run: bash <(curl -s https://codecov.io/bash)
- run: make dist
- run: |
unzip dist/gh/kubelogin_linux_amd64.zip -d /tmp
file /tmp/kubelogin
/tmp/kubelogin --help
- run: |
if [ "$CIRCLE_TAG" ]; then
make release
fi
workflows:
version: 2
all:
jobs:
- build:
context: open-source
filters:
tags:
only: /.*/

20
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,20 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
## Describe the issue
A clear and concise description of what the issue is.
## To reproduce
A console log or steps to reproduce the issue.
## Your environment
- OS: e.g. macOS
- kubelogin version: e.g. v1.19
- kubectl version: e.g. v1.19
- OpenID Connect provider: e.g. Google

View File

@@ -0,0 +1,15 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: enhancement
assignees: ''
---
## Purpose of the feature (why)
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
A clear and concise description of what you want to happen.
## Your idea (how)
A clear and concise description of any alternative solutions or features you've considered.

20
.github/ISSUE_TEMPLATE/question.md vendored Normal file
View File

@@ -0,0 +1,20 @@
---
name: Question
about: Feel free to ask a question
title: ''
labels: question
assignees: ''
---
## Describe the question
A clear and concise description of what the issue is.
## To reproduce
A console log or steps to reproduce the issue.
## Your environment
- OS: e.g. macOS
- kubelogin version: e.g. v1.19
- kubectl version: e.g. v1.19
- OpenID Connect provider: e.g. Google

10
.github/renovate.json5 vendored Normal file
View File

@@ -0,0 +1,10 @@
{
"$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",
],
}

76
.github/workflows/docker.yaml vendored Normal file
View File

@@ -0,0 +1,76 @@
name: docker
on:
pull_request:
branches:
- master
paths:
- .github/workflows/docker.yaml
- pkg/**
- go.*
- Dockerfile
- Makefile
push:
branches:
- master
paths:
- .github/workflows/docker.yaml
- 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
outputs:
image-uri: ghcr.io/${{ github.repository }}@${{ steps.build.outputs.digest }}
steps:
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/metadata-action@v5
id: metadata
with:
images: ghcr.io/${{ github.repository }}
- uses: int128/docker-manifest-create-action@v2
id: build
with:
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 }}
test:
needs: build
runs-on: ubuntu-latest
steps:
- run: docker run --rm '${{ needs.build.outputs.image-uri }}' --help

36
.github/workflows/go.yaml vendored Normal file
View File

@@ -0,0 +1,36 @@
name: go
on:
push:
branches:
- master
paths:
- .github/workflows/go.yaml
- pkg/**
- go.*
tags:
- v*
pull_request:
branches:
- master
paths:
- .github/workflows/go.yaml
- pkg/**
- go.*
jobs:
check:
uses: int128/go-workflows/.github/workflows/check.yaml@v0.3.0
with:
go-version: 1.22.5
golangci-lint-version: v1.59.1
test:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: 1.22.5
- run: go test -v -race ./...

74
.github/workflows/release.yaml vendored Normal file
View File

@@ -0,0 +1,74 @@
name: release
on:
push:
branches:
- master
paths:
- .github/workflows/release.yaml
- pkg/**
- go.*
tags:
- v*
pull_request:
branches:
- master
paths:
- .github/workflows/release.yaml
- pkg/**
- go.*
jobs:
build:
strategy:
matrix:
platform:
- runs-on: ubuntu-latest
GOOS: linux
GOARCH: amd64
CGO_ENABLED: 0 # https://github.com/int128/kubelogin/issues/567
- runs-on: ubuntu-latest
GOOS: linux
GOARCH: arm64
- runs-on: ubuntu-latest
GOOS: linux
GOARCH: arm
- runs-on: ubuntu-latest
GOOS: linux
GOARCH: ppc64le
- runs-on: macos-latest
GOOS: darwin
GOARCH: amd64
CGO_ENABLED: 1 # https://github.com/int128/kubelogin/issues/249
- runs-on: macos-latest
GOOS: darwin
GOARCH: arm64
CGO_ENABLED: 1 # https://github.com/int128/kubelogin/issues/762
- runs-on: windows-latest
GOOS: windows
GOARCH: amd64
runs-on: ${{ matrix.platform.runs-on }}
env:
GOOS: ${{ matrix.platform.GOOS }}
GOARCH: ${{ matrix.platform.GOARCH }}
CGO_ENABLED: ${{ matrix.platform.CGO_ENABLED }}
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: 1.22.5
- run: go build -ldflags '-X main.version=${{ github.ref_name }}'
- uses: int128/go-release-action@v2
with:
binary: kubelogin
publish:
if: github.ref_type == 'tag'
needs:
- build
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: rajatjindal/krew-release-bot@v0.0.46

41
.github/workflows/system-test.yaml vendored Normal file
View File

@@ -0,0 +1,41 @@
name: system-test
on:
pull_request:
branches:
- master
paths:
- .github/workflows/system-test.yaml
- system_test/**
- pkg/**
- go.*
push:
branches:
- master
paths:
- .github/workflows/system-test.yaml
- system_test/**
- pkg/**
- go.*
jobs:
system-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: 1.22.5
# for certutil
# https://packages.ubuntu.com/xenial/libnss3-tools
- run: sudo apt update
- run: sudo apt install -y libnss3-tools
- run: mkdir -p ~/.pki/nssdb
- run: echo '127.0.0.1 dex-server' | sudo tee -a /etc/hosts
- run: make -C system_test -j3
- run: make -C system_test logs
if: always()

5
.gitignore vendored
View File

@@ -1,9 +1,10 @@
/.idea
/.kubeconfig*
/acceptance_test/output/
/dist
/coverage.out
/kubelogin
/kubectl-oidc_login
/kubelogin_*.zip
/kubelogin_*.zip.sha256

62
.krew.yaml Normal file
View File

@@ -0,0 +1,62 @@
apiVersion: krew.googlecontainertools.github.com/v1alpha2
kind: Plugin
metadata:
name: oidc-login
spec:
homepage: https://github.com/int128/kubelogin
shortDescription: Log in to the OpenID Connect provider
description: |
This is a kubectl plugin for Kubernetes OpenID Connect (OIDC) authentication.
## Credential plugin mode
kubectl executes oidc-login before calling the Kubernetes APIs.
oidc-login automatically opens the browser and you can log in to the provider.
After authentication, kubectl gets the token from oidc-login and you can access the cluster.
See https://github.com/int128/kubelogin#credential-plugin-mode for more.
## Standalone mode
Run `kubectl oidc-login`.
It automatically opens the browser and you can log in to the provider.
After authentication, it writes the token to the kubeconfig and you can access the cluster.
See https://github.com/int128/kubelogin#standalone-mode for more.
caveats: |
You need to setup the OIDC provider, Kubernetes API server, role binding and kubeconfig.
version: {{ .TagName }}
platforms:
- bin: kubelogin
{{ addURIAndSha "https://github.com/int128/kubelogin/releases/download/{{ .TagName }}/kubelogin_linux_amd64.zip" .TagName }}
selector:
matchLabels:
os: linux
arch: amd64
- bin: kubelogin
{{ addURIAndSha "https://github.com/int128/kubelogin/releases/download/{{ .TagName }}/kubelogin_linux_arm64.zip" .TagName }}
selector:
matchLabels:
os: linux
arch: arm64
- bin: kubelogin
{{ addURIAndSha "https://github.com/int128/kubelogin/releases/download/{{ .TagName }}/kubelogin_linux_arm.zip" .TagName }}
selector:
matchLabels:
os: linux
arch: arm
- bin: kubelogin
{{ addURIAndSha "https://github.com/int128/kubelogin/releases/download/{{ .TagName }}/kubelogin_darwin_amd64.zip" .TagName }}
selector:
matchLabels:
os: darwin
arch: amd64
- bin: kubelogin
{{ addURIAndSha "https://github.com/int128/kubelogin/releases/download/{{ .TagName }}/kubelogin_darwin_arm64.zip" .TagName }}
selector:
matchLabels:
os: darwin
arch: arm64
- bin: kubelogin.exe
{{ addURIAndSha "https://github.com/int128/kubelogin/releases/download/{{ .TagName }}/kubelogin_windows_amd64.zip" .TagName }}
selector:
matchLabels:
os: windows
arch: amd64

12
Dockerfile Normal file
View File

@@ -0,0 +1,12 @@
FROM golang:1.22 as builder
WORKDIR /builder
COPY go.* .
RUN go mod download
COPY main.go .
COPY pkg pkg
RUN go build
FROM gcr.io/distroless/base-debian12
COPY --from=builder /builder/kubelogin /
ENTRYPOINT ["/kubelogin"]

View File

@@ -1,37 +0,0 @@
TARGET := kubelogin
CIRCLE_TAG ?= HEAD
LDFLAGS := -X main.version=$(CIRCLE_TAG)
all: $(TARGET)
.PHONY: check
check:
golangci-lint run
go test -v -race -cover -coverprofile=coverage.out ./...
$(TARGET): $(wildcard *.go)
go build -o $@ -ldflags "$(LDFLAGS)"
dist:
# make the zip files for GitHub Releases
VERSION=$(CIRCLE_TAG) CGO_ENABLED=0 goxzst -d dist/gh/ -i "LICENSE" -o "$(TARGET)" -t "kubelogin.rb oidc-login.yaml" -- -ldflags "$(LDFLAGS)"
zipinfo dist/gh/kubelogin_linux_amd64.zip
# make the Homebrew formula
mv dist/gh/kubelogin.rb dist/
# make the yaml for krew-index
mkdir -p dist/plugins
cp dist/gh/oidc-login.yaml dist/plugins/oidc-login.yaml
.PHONY: release
release: dist
# publish to the GitHub Releases
ghr -u "$(CIRCLE_PROJECT_USERNAME)" -r "$(CIRCLE_PROJECT_REPONAME)" "$(CIRCLE_TAG)" dist/gh/
# publish to the Homebrew tap repository
ghcp commit -u "$(CIRCLE_PROJECT_USERNAME)" -r "homebrew-$(CIRCLE_PROJECT_REPONAME)" -m "$(CIRCLE_TAG)" -C dist/ kubelogin.rb
# fork krew-index and create a branch
ghcp fork-commit -u kubernetes-sigs -r krew-index -b "oidc-login-$(CIRCLE_TAG)" -m "Bump oidc-login to $(CIRCLE_TAG)" -C dist/ plugins/oidc-login.yaml
.PHONY: clean
clean:
-rm $(TARGET)
-rm -r dist/

228
README.md
View File

@@ -1,10 +1,10 @@
# kubelogin [![CircleCI](https://circleci.com/gh/int128/kubelogin.svg?style=shield)](https://circleci.com/gh/int128/kubelogin) [![Go Report Card](https://goreportcard.com/badge/github.com/int128/kubelogin)](https://goreportcard.com/report/github.com/int128/kubelogin)
# kubelogin [![go](https://github.com/int128/kubelogin/actions/workflows/go.yaml/badge.svg)](https://github.com/int128/kubelogin/actions/workflows/go.yaml) [![Go Report Card](https://goreportcard.com/badge/github.com/int128/kubelogin)](https://goreportcard.com/report/github.com/int128/kubelogin)
This is a kubectl plugin for [Kubernetes OpenID Connect (OIDC) authentication](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#openid-connect-tokens), also known as `kubectl oidc-login`.
Here is an example of Kubernetes authentication with the Google Identity Platform:
<img alt="screencast" src="https://user-images.githubusercontent.com/321266/70971501-7bcebc80-20e4-11ea-8afc-539dcaea0aa8.gif" width="652" height="455">
<img alt="screencast" src="https://user-images.githubusercontent.com/321266/85427290-86e43700-b5b6-11ea-9e97-ffefd736c9b7.gif" width="572" height="391">
Kubelogin is designed to run as a [client-go credential plugin](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins).
When you run kubectl, kubelogin opens the browser and you can log in to the provider.
@@ -18,21 +18,21 @@ Take a look at the diagram:
### Setup
Install the latest release from [Homebrew](https://brew.sh/), [Krew](https://github.com/kubernetes-sigs/krew) or [GitHub Releases](https://github.com/int128/kubelogin/releases) as follows:
Install the latest release from [Homebrew](https://brew.sh/), [Krew](https://github.com/kubernetes-sigs/krew), [Chocolatey](https://chocolatey.org/packages/kubelogin) or [GitHub Releases](https://github.com/int128/kubelogin/releases).
```sh
# Homebrew
# Homebrew (macOS and Linux)
brew install int128/kubelogin/kubelogin
# Krew
# Krew (macOS, Linux, Windows and ARM)
kubectl krew install oidc-login
# GitHub Releases
curl -LO https://github.com/int128/kubelogin/releases/download/v1.15.0/kubelogin_linux_amd64.zip
unzip kubelogin_linux_amd64.zip
ln -s kubelogin kubectl-oidc_login
# Chocolatey (Windows)
choco install kubelogin
```
If you install via GitHub releases, you need to put the `kubelogin` binary on your path under the name `kubectl-oidc_login` so that the [kubectl plugin mechanism](https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/) can find it when you invoke `kubectl oidc-login`. The other install methods do this for you.
You need to set up the OIDC provider, cluster role binding, Kubernetes API server and kubeconfig.
The kubeconfig looks like:
@@ -51,7 +51,7 @@ users:
- --oidc-client-secret=YOUR_CLIENT_SECRET
```
See [the setup guide](docs/setup.md) for more.
See [setup guide](docs/setup.md) for more.
### Run
@@ -63,11 +63,11 @@ kubectl get pods
```
Kubectl executes kubelogin before calling the Kubernetes APIs.
Kubelogin automatically opens the browser and you can log in to the provider.
Kubelogin automatically opens the browser, and you can log in to the provider.
<img src="docs/keycloak-login.png" alt="keycloak-login" width="455" height="329">
After authentication, kubelogin returns the credentials to kubectl and finally kubectl calls the Kubernetes APIs with the credential.
After authentication, kubelogin returns the credentials to kubectl and kubectl then calls the Kubernetes APIs with these credentials.
```
% kubectl get pods
@@ -80,180 +80,54 @@ Kubelogin writes the ID token and refresh token to the token cache file.
If the cached ID token is valid, kubelogin just returns it.
If the cached ID token has expired, kubelogin will refresh the token using the refresh token.
If the refresh token has expired, kubelogin will perform reauthentication.
If the refresh token has expired, kubelogin will perform re-authentication (you will have to login via browser again).
### Troubleshoot
You can log out by removing the token cache directory (default `~/.kube/cache/oidc-login`).
Kubelogin will perform authentication if the token cache file does not exist.
Kubelogin will ask you to login via browser again if the token cache file does not exist i.e., it starts with a clean slate
You can dump the claims of token by passing `-v1` option.
You can dump claims of an ID token by `setup` command.
```
I1212 10:14:17.754394 2517 get_token.go:91] the ID token has the claim: sub=********
I1212 10:14:17.754434 2517 get_token.go:91] the ID token has the claim: at_hash=********
I1212 10:14:17.754449 2517 get_token.go:91] the ID token has the claim: nonce=********
I1212 10:14:17.754459 2517 get_token.go:91] the ID token has the claim: iat=1576113256
I1212 10:14:17.754467 2517 get_token.go:91] the ID token has the claim: exp=1576116856
I1212 10:14:17.754484 2517 get_token.go:91] the ID token has the claim: iss=https://accounts.google.com
I1212 10:14:17.754497 2517 get_token.go:91] the ID token has the claim: azp=********.apps.googleusercontent.com
I1212 10:14:17.754506 2517 get_token.go:91] the ID token has the claim: aud=********.apps.googleusercontent.com
```console
% kubectl oidc-login setup --oidc-issuer-url https://accounts.google.com --oidc-client-id REDACTED --oidc-client-secret REDACTED
...
You got a token with the following claims:
{
"sub": "********",
"iss": "https://accounts.google.com",
"aud": "********",
...
}
```
## Usage
This document is for the development version.
If you are looking for a specific version, see [the release tags](https://github.com/int128/kubelogin/tags).
Kubelogin supports the following options:
```
% kubectl oidc-login get-token -h
Run as a kubectl credential plugin
Usage:
kubelogin get-token [flags]
Flags:
--oidc-issuer-url string Issuer URL of the provider (mandatory)
--oidc-client-id string Client ID of the provider (mandatory)
--oidc-client-secret string Client secret of the provider
--oidc-extra-scope strings Scopes to request to the provider
--certificate-authority string Path to a cert file for the certificate authority
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--token-cache-dir string Path to a directory for caching tokens (default "~/.kube/cache/oidc-login")
--grant-type string The authorization grant type to use. One of (auto|authcode|authcode-keyboard|password) (default "auto")
--listen-port ints Port to bind to the local server. If multiple ports are given, it will try the ports in order (default [8000,18000])
--skip-open-browser If true, it does not open the browser on authentication
--username string If set, perform the resource owner password credentials grant
--password string If set, use the password instead of asking it
-h, --help help for get-token
Global Flags:
--add_dir_header If true, adds the file directory to the header
--alsologtostderr log to standard error as well as files
--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)
--logtostderr log to standard error instead of files (default 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)
-v, --v Level number for the log level verbosity
--vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
```
See also the options of [standalone mode](docs/standalone-mode.md).
### Extra scopes
You can set the extra scopes to request to the provider by `--oidc-extra-scope`.
You can increase the log level by `-v1` option.
```yaml
- --oidc-extra-scope=email
- --oidc-extra-scope=profile
users:
- name: oidc
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: kubectl
args:
- oidc-login
- get-token
- -v1
```
### CA Certificates
You can use your self-signed certificate for the provider.
```yaml
- --certificate-authority=/home/user/.kube/keycloak-ca.pem
```
### HTTP Proxy
You can set the following environment variables if you are behind a proxy: `HTTP_PROXY`, `HTTPS_PROXY` and `NO_PROXY`.
See also [net/http#ProxyFromEnvironment](https://golang.org/pkg/net/http/#ProxyFromEnvironment).
You can verify kubelogin works with your provider using [acceptance test](acceptance_test).
### Authentication flows
## Docs
#### Authorization code flow
Kubelogin performs the authorization code flow by default.
It starts the local server at port 8000 or 18000 by default.
You need to register the following redirect URIs to the provider:
- `http://localhost:8000`
- `http://localhost:18000` (used if port 8000 is already in use)
You can change the ports by the option:
```yaml
- --listen-port=12345
- --listen-port=23456
```
#### Authorization code flow with keyboard interactive
If you cannot access the browser, instead use the authorization code flow with keyboard interactive.
```yaml
- --grant-type=authcode-keyboard
```
Kubelogin will show the URL and prompt.
Open the URL in the browser and then copy the code shown.
```
% kubectl get pods
Open https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&client_id=...
Enter code: YOUR_CODE
```
Note that this flow uses the redirect URI `urn:ietf:wg:oauth:2.0:oob` and
some OIDC providers do not support it.
#### Resource owner password credentials grant flow
Kubelogin performs the resource owner password credentials grant flow
when `--grant-type=password` or `--username` is set.
Note that most OIDC providers do not support this flow.
Keycloak supports this flow but you need to explicitly enable the "Direct Access Grants" feature in the client settings.
You can set the username and password.
```yaml
- --username=USERNAME
- --password=PASSWORD
```
If the password is not set, kubelogin will show the prompt for the password.
```yaml
- --username=USERNAME
```
```
% kubectl get pods
Password:
```
If the username is not set, kubelogin will show the prompt for the username and password.
```yaml
- --grant-type=password
```
```
% kubectl get pods
Username: foo
Password:
```
## Related works
### Kubernetes Dashboard
You can access the Kubernetes Dashboard using kubelogin and [kauthproxy](https://github.com/int128/kauthproxy).
- [Setup guide](docs/setup.md)
- [Usage and options](docs/usage.md)
- [Standalone mode](docs/standalone-mode.md)
- [System test](system_test)
- [Acceptance_test for identity providers](acceptance_test)
## Contributions
@@ -261,15 +135,5 @@ You can access the Kubernetes Dashboard using kubelogin and [kauthproxy](https:/
This is an open source software licensed under Apache License 2.0.
Feel free to open issues and pull requests for improving code and documents.
### Development
Go 1.13 or later is required.
```sh
# Run lint and tests
make check
# Compile and run the command
make
./kubelogin
```
This software is developed with [GoLand](https://www.jetbrains.com/go/) licensed for open source development.
Special thanks for the support.

42
acceptance_test/Makefile Normal file
View File

@@ -0,0 +1,42 @@
CLUSTER_NAME := kubelogin-acceptance-test
OUTPUT_DIR := $(CURDIR)/output
KUBECONFIG := $(OUTPUT_DIR)/kubeconfig.yaml
export KUBECONFIG
# create a Kubernetes cluster
.PHONY: cluster
cluster:
# create a cluster
mkdir -p $(OUTPUT_DIR)
sed -e "s|OIDC_ISSUER_URL|$(OIDC_ISSUER_URL)|" -e "s|OIDC_CLIENT_ID|$(OIDC_CLIENT_ID)|" cluster.yaml > $(OUTPUT_DIR)/cluster.yaml
kind create cluster --name $(CLUSTER_NAME) --config $(OUTPUT_DIR)/cluster.yaml
# set up access control
kubectl create clusterrole cluster-readonly --verb=get,watch,list --resource='*.*'
kubectl create clusterrolebinding cluster-readonly --clusterrole=cluster-readonly --user=$(YOUR_EMAIL)
# set up kubectl
kubectl config set-credentials oidc \
--exec-api-version=client.authentication.k8s.io/v1beta1 \
--exec-command=$(CURDIR)/../kubelogin \
--exec-arg=get-token \
--exec-arg=--token-cache-dir=$(OUTPUT_DIR)/token-cache \
--exec-arg=--oidc-issuer-url=$(OIDC_ISSUER_URL) \
--exec-arg=--oidc-client-id=$(OIDC_CLIENT_ID) \
--exec-arg=--oidc-client-secret=$(OIDC_CLIENT_SECRET) \
--exec-arg=--oidc-extra-scope=email
# switch the default user
kubectl config set-context --current --user=oidc
# clean up the resources
.PHONY: clean
clean:
-rm -r $(OUTPUT_DIR)
.PHONY: delete-cluster
delete-cluster:
kind delete cluster --name $(CLUSTER_NAME)
.PHONY: check
check:
docker version
kind version
kubectl version --client

75
acceptance_test/README.md Normal file
View File

@@ -0,0 +1,75 @@
# kubelogin/acceptance_test
This is a manual test for verifying Kubernetes OIDC authentication with your OIDC provider.
## Purpose
This test checks the following points:
1. You can set up your OIDC provider using [setup guide](../docs/setup.md).
1. The plugin works with your OIDC provider.
## Getting Started
### Prerequisite
You need to build the plugin into the parent directory.
```sh
make -C ..
```
You need to set up your provider.
See [setup guide](../docs/setup.md) for more.
You need to install the following tools:
- Docker
- Kind
- kubectl
You can check if the tools are available.
```sh
make check
```
### 1. Create a cluster
Create a cluster.
For example, you can create a cluster with Google account authentication.
```sh
make OIDC_ISSUER_URL=https://accounts.google.com \
OIDC_CLIENT_ID=REDACTED.apps.googleusercontent.com \
OIDC_CLIENT_SECRET=REDACTED \
YOUR_EMAIL=REDACTED@gmail.com
```
It will do the following steps:
1. Create a cluster.
1. Set up access control. It allows read-only access from your email address.
1. Set up kubectl to enable the plugin.
You can change kubectl configuration in generated `output/kubeconfig.yaml`.
### 2. Run kubectl
Make sure you can log in to the provider and access the cluster.
```console
% export KUBECONFIG=$PWD/output/kubeconfig.yaml
% kubectl get pods -A
```
### Clean up
To delete the cluster and generated files:
```sh
make delete-cluster
make clean
```

View File

@@ -0,0 +1,13 @@
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
kubeadmConfigPatches:
- |
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
metadata:
name: config
apiServer:
extraArgs:
oidc-issuer-url: OIDC_ISSUER_URL
oidc-client-id: OIDC_CLIENT_ID
oidc-username-claim: email

View File

@@ -1,6 +1,6 @@
# Kubernetes OpenID Connection authentication
This document guides how to set up the Kubernetes OpenID Connect (OIDC) authentication.
This document guides how to set up Kubernetes OpenID Connect (OIDC) authentication.
Let's see the following steps:
1. Set up the OIDC provider
@@ -35,7 +35,7 @@ Variable | Value
You can log in with a user of Keycloak.
Make sure you have an administrator role of the Keycloak realm.
Open the Keycloak and create an OIDC client as follows:
Open Keycloak and create an OIDC client as follows:
- Client ID: `YOUR_CLIENT_ID`
- Valid Redirect URLs:
@@ -52,7 +52,7 @@ You can associate client roles by adding the following mapper:
- Token Claim Name: `groups`
- Add to ID token: on
For example, if you have the `admin` role of the client, you will get a JWT with the claim `{"groups": ["kubernetes:admin"]}`.
For example, if you have `admin` role of the client, you will get a JWT with the claim `{"groups": ["kubernetes:admin"]}`.
Replace the following variables in the later sections.
@@ -72,7 +72,7 @@ Open [GitHub OAuth Apps](https://github.com/settings/developers) and create an a
- Homepage URL: `https://dex.example.com`
- Authorization callback URL: `https://dex.example.com/callback`
Deploy the [dex](https://github.com/dexidp/dex) with the following config:
Deploy [Dex](https://github.com/dexidp/dex) with the following config:
```yaml
issuer: https://dex.example.com
@@ -126,6 +126,28 @@ Variable | Value
You do not need to set `YOUR_CLIENT_SECRET`.
If you need `groups` claim for access control,
see [jetstack/okta-kubectl-auth](https://github.com/jetstack/okta-kubectl-auth/blob/master/docs/okta-setup.md) and [#250](https://github.com/int128/kubelogin/issues/250).
### Ping Identity
Login with an account that has permissions to create applications.
Create an OIDC application with the following configuration:
- Redirect URIs:
- `http://localhost:8000`
- `http://localhost:18000` (used if the port 8000 is already in use)
- Grant type: Authorization Code
- PKCE Enforcement: Required
Leverage the following variables in the next steps.
Variable | Value
------------------------|------
`ISSUER_URL` | `https://auth.pingone.com/<PingOne Tenant Id>/as`
`YOUR_CLIENT_ID` | random string
`YOUR_CLIENT_SECRET` is not required for this configuration.
## 2. Verify authentication
@@ -138,31 +160,23 @@ kubectl oidc-login setup \
--oidc-client-secret=YOUR_CLIENT_SECRET
```
It will open the browser and you can log in to the provider.
Then it will show the instruction.
It launches the browser and navigates to `http://localhost:8000`.
Please log in to the provider.
You can set extra options, for example, extra scope or CA certificate.
See also the full options.
```sh
kubectl oidc-login setup --help
```
## 3. Bind a cluster role
In this tutorial, bind the `cluster-admin` role to you.
Apply the following manifest:
```yaml
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: oidc-cluster-admin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: User
name: ISSUER_URL#YOUR_SUBJECT
```
Here bind `cluster-admin` role to you.
```sh
kubectl apply -f oidc-cluster-admin.yaml
kubectl create clusterrolebinding oidc-cluster-admin --clusterrole=cluster-admin --user='ISSUER_URL#YOUR_SUBJECT'
```
As well as you can create a custom cluster role and bind it.
@@ -170,14 +184,14 @@ As well as you can create a custom cluster role and bind it.
## 4. Set up the Kubernetes API server
Add the following options to the kube-apiserver:
Add the following flags to kube-apiserver:
```
--oidc-issuer-url=ISSUER_URL
--oidc-client-id=YOUR_CLIENT_ID
```
See [OpenID Connect Tokens](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#openid-connect-tokens) for details.
See [Kubernetes Authenticating: OpenID Connect Tokens](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#openid-connect-tokens) for the all flags.
If you are using [kops](https://github.com/kubernetes/kops), run `kops edit cluster` and append the following settings:
@@ -200,35 +214,32 @@ If you are using [kube-aws](https://github.com/kubernetes-incubator/kube-aws), a
## 5. Set up the kubeconfig
Add the following user to the kubeconfig:
Add `oidc` user to the kubeconfig.
```yaml
users:
- name: oidc
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: kubectl
args:
- oidc-login
- get-token
- --oidc-issuer-url=ISSUER_URL
- --oidc-client-id=YOUR_CLIENT_ID
- --oidc-client-secret=YOUR_CLIENT_SECRET
```sh
kubectl config set-credentials oidc \
--exec-api-version=client.authentication.k8s.io/v1beta1 \
--exec-command=kubectl \
--exec-arg=oidc-login \
--exec-arg=get-token \
--exec-arg=--oidc-issuer-url=ISSUER_URL \
--exec-arg=--oidc-client-id=YOUR_CLIENT_ID \
--exec-arg=--oidc-client-secret=YOUR_CLIENT_SECRET
```
You can share the kubeconfig to your team members for on-boarding.
## 6. Verify cluster access
Make sure you can access the Kubernetes cluster.
```sh
kubectl --user=oidc cluster-info
```
% kubectl get nodes
Open http://localhost:8000 for authentication
You got a valid token until 2019-05-16 22:03:13 +0900 JST
NAME STATUS ROLES AGE VERSION
ip-1-2-3-4.us-west-2.compute.internal Ready node 21d v1.9.6
ip-1-2-3-5.us-west-2.compute.internal Ready node 20d v1.9.6
You can switch the current context to oidc.
```sh
kubectl config set-context --current --user=oidc
```
You can share the kubeconfig to your team members for on-boarding.

View File

@@ -1,9 +1,12 @@
# Standalone mode
You can run kubelogin as a standalone command.
In this mode, you need to manually run the command before running kubectl.
Kubelogin supports the standalone mode as well.
It writes the token to the kubeconfig (typically `~/.kube/config`) after authentication.
Configure the kubeconfig like:
## Getting started
Configure your kubeconfig like:
```yaml
- name: keycloak
@@ -31,7 +34,7 @@ It automatically opens the browser and you can log in to the provider.
After authentication, kubelogin writes the ID token and refresh token to the kubeconfig.
```
```console
% kubelogin
Open http://localhost:8000 for authentication
You got a valid token until 2019-05-18 10:28:51 +0900 JST
@@ -40,7 +43,7 @@ Updated ~/.kubeconfig
Now you can access the cluster.
```
```console
% kubectl get pods
NAME READY STATUS RESTARTS AGE
echoserver-86c78fdccd-nzmd5 1/1 Running 0 26d
@@ -64,7 +67,7 @@ users:
If the ID token is valid, kubelogin does nothing.
```
```console
% kubelogin
You already have a valid token until 2019-05-18 10:28:51 +0900 JST
```
@@ -75,58 +78,6 @@ If the refresh token has expired, kubelogin will proceed the authentication.
## Usage
Kubelogin supports the following options:
```
% kubectl oidc-login -h
Login to the OpenID Connect provider.
You need to set up the OIDC provider, role binding, Kubernetes API server and kubeconfig.
Run the following command to show the setup instruction:
kubectl oidc-login setup
See https://github.com/int128/kubelogin for more.
Usage:
main [flags]
main [command]
Available Commands:
get-token Run as a kubectl credential plugin
help Help about any command
setup Show the setup instruction
version Print the version information
Flags:
--kubeconfig string Path to the kubeconfig file
--context string The name of the kubeconfig context to use
--user string The name of the kubeconfig user to use. Prior to --context
--certificate-authority string Path to a cert file for the certificate authority
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--grant-type string The authorization grant type to use. One of (auto|authcode|authcode-keyboard|password) (default "auto")
--listen-port ints Port to bind to the local server. If multiple ports are given, it will try the ports in order (default [8000,18000])
--skip-open-browser If true, it does not open the browser on authentication
--username string If set, perform the resource owner password credentials grant
--password string If set, use the password instead of asking it
--add_dir_header If true, adds the file directory to the header
--alsologtostderr log to standard error as well as files
--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)
--logtostderr log to standard error instead of files (default 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)
-v, --v Level number for the log level verbosity
--vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
-h, --help help for main
--version version for main
```
### Kubeconfig
You can set path to the kubeconfig file by the option or the environment variable just like kubectl.
It defaults to `~/.kube/config`.
@@ -154,26 +105,4 @@ Key | Direction | Value
`id-token` | Write | ID token got from the provider.
`refresh-token` | Write | Refresh token got from the provider.
### Extra scopes
You can set the extra scopes to request to the provider by `extra-scopes` in the kubeconfig.
```sh
kubectl config set-credentials keycloak --auth-provider-arg extra-scopes=email
```
Currently kubectl does not accept multiple scopes, so you need to edit the kubeconfig as like:
```sh
kubectl config set-credentials keycloak --auth-provider-arg extra-scopes=SCOPES
sed -i '' -e s/SCOPES/email,profile/ $KUBECONFIG
```
### CA Certificates
You can use your self-signed certificates for the provider.
```sh
kubectl config set-credentials keycloak \
--auth-provider-arg idp-certificate-authority=$HOME/.kube/keycloak-ca.pem
```
See also [usage.md](usage.md).

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 28 KiB

259
docs/usage.md Normal file
View File

@@ -0,0 +1,259 @@
# Usage
Kubelogin supports the following options:
```
Usage:
kubelogin get-token [flags]
Flags:
--oidc-issuer-url string Issuer URL of the provider (mandatory)
--oidc-client-id string Client ID of the provider (mandatory)
--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
--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
--certificate-authority-data stringArray Base64 encoded cert for the certificate authority
--insecure-skip-tls-verify If set, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--tls-renegotiation-once If set, allow a remote server to request renegotiation once per connection
--tls-renegotiation-freely If set, allow a remote server to repeatedly request renegotiation
--grant-type string Authorization grant type to use. One of (auto|authcode|authcode-keyboard|password|device-code) (default "auto")
--listen-address strings [authcode] Address to bind to the local server. If multiple addresses are set, it will try binding in order (default [127.0.0.1:8000,127.0.0.1:18000])
--skip-open-browser [authcode] Do not open the browser automatically
--browser-command string [authcode] Command to open the browser
--authentication-timeout-sec int [authcode] Timeout of authentication in seconds (default 180)
--local-server-cert string [authcode] Certificate path for the local server
--local-server-key string [authcode] Certificate key path for the local server
--open-url-after-authentication string [authcode] If set, open the URL in the browser after authentication
--oidc-redirect-url-hostname string [authcode] Hostname of the redirect URL (default "localhost")
--oidc-redirect-url-authcode-keyboard string [authcode-keyboard] Redirect URL (default "urn:ietf:wg:oauth:2.0:oob")
--oidc-auth-request-extra-params stringToString [authcode, authcode-keyboard] Extra query parameters to send with an authentication request (default [])
--username string [password] Username for resource owner password credentials grant
--password string [password] Password for resource owner password credentials grant
-h, --help help for get-token
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
--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)
--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)
--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)
-v, --v Level number for the log level verbosity
--vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
```
## Options
### Authentication timeout
By default, you need to log in to your provider in the browser within 3 minutes.
This prevents a process from remaining forever.
You can change the timeout by the following flag:
```yaml
- --authentication-timeout-sec=60
```
For now this timeout works only for the authorization code flow.
### Extra scopes
You can set the extra scopes to request to the provider by `--oidc-extra-scope`.
```yaml
- --oidc-extra-scope=email
- --oidc-extra-scope=profile
```
### CA certificate
You can use your self-signed certificate for the provider.
```yaml
- --certificate-authority=/home/user/.kube/keycloak-ca.pem
- --certificate-authority-data=LS0t...
```
### HTTP proxy
You can set the following environment variables if you are behind a proxy: `HTTP_PROXY`, `HTTPS_PROXY` and `NO_PROXY`.
See also [net/http#ProxyFromEnvironment](https://golang.org/pkg/net/http/#ProxyFromEnvironment).
### Home directory expansion
If a value in the following options begins with a tilde character `~`, it is expanded to the home directory.
- `--certificate-authority`
- `--local-server-cert`
- `--local-server-key`
- `--token-cache-dir`
## Authentication flows
Kubelogin support the following flows:
- Authorization code flow
- Authorization code flow with a keyboard
- Resource owner password credentials grant flow
### Authorization code flow
Kubelogin performs the authorization code flow by default.
It starts the local server at port 8000 or 18000 by default.
You need to register the following redirect URIs to the provider:
- `http://localhost:8000`
- `http://localhost:18000` (used if port 8000 is already in use)
You can change the listening address.
```yaml
- --listen-address=127.0.0.1:12345
- --listen-address=127.0.0.1:23456
```
You can specify a certificate for the local webserver if HTTPS is required by your identity provider.
```yaml
- --local-server-cert=localhost.crt
- --local-server-key=localhost.key
```
You can change the hostname of redirect URI from the default value `localhost`.
```yaml
- --oidc-redirect-url-hostname=127.0.0.1
```
You can add extra parameters to the authentication request.
```yaml
- --oidc-auth-request-extra-params=ttl=86400
```
When authentication completed, kubelogin shows a message to close the browser.
You can change the URL to show after authentication.
```yaml
- --open-url-after-authentication=https://example.com/success.html
```
You can skip opening the browser if you encounter some environment problem.
```yaml
- --skip-open-browser
```
For Linux users, you change the default browser by `BROWSER` environment variable.
### Authorization code flow with a keyboard
If you cannot access the browser, instead use the authorization code flow with a keyboard.
```yaml
- --grant-type=authcode-keyboard
```
Kubelogin will show the URL and prompt.
Open the URL in the browser and then copy the code shown.
```
% kubectl get pods
Open https://accounts.google.com/o/oauth2/v2/auth?access_type=offline&client_id=...
Enter code: YOUR_CODE
```
The default of redirect URI is `urn:ietf:wg:oauth:2.0:oob`.
You can overwrite it.
```yaml
- oidc-redirect-url-authcode-keyboard=http://localhost
```
You can add extra parameters to the authentication request.
```yaml
- --oidc-auth-request-extra-params=ttl=86400
```
### Resource owner password credentials grant flow
Kubelogin performs the resource owner password credentials grant flow
when `--grant-type=password` or `--username` is set.
Note that most OIDC providers do not support this flow.
Keycloak supports this flow but you need to explicitly enable the "Direct Access Grants" feature in the client settings.
You can set the username and password.
```yaml
- --username=USERNAME
- --password=PASSWORD
```
If the password is not set, kubelogin will show the prompt for the password.
```yaml
- --username=USERNAME
```
```
% kubectl get pods
Password:
```
If the username is not set, kubelogin will show the prompt for the username and password.
```yaml
- --grant-type=password
```
```
% kubectl get pods
Username: foo
Password:
```
## Run in Docker
You can run [the Docker image](https://ghcr.io/int128/kubelogin) instead of the binary.
The kubeconfig looks like:
```yaml
users:
- name: oidc
user:
exec:
apiVersion: client.authentication.k8s.io/v1beta1
command: docker
args:
- run
- --rm
- -v
- /tmp/.token-cache:/.token-cache
- -p
- 8000:8000
- ghcr.io/int128/kubelogin
- get-token
- --token-cache-dir=/.token-cache
- --listen-address=0.0.0.0:8000
- --oidc-issuer-url=ISSUER_URL
- --oidc-client-id=YOUR_CLIENT_ID
- --oidc-client-secret=YOUR_CLIENT_SECRET
```
Known limitations:
- It cannot open the browser automatically.
- The container port and listen port must be equal for consistency of the redirect URI.

View File

@@ -1,299 +0,0 @@
package e2e_test
import (
"context"
"io/ioutil"
"os"
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/google/go-cmp/cmp"
"github.com/int128/kubelogin/e2e_test/idp"
"github.com/int128/kubelogin/e2e_test/idp/mock_idp"
"github.com/int128/kubelogin/e2e_test/keys"
"github.com/int128/kubelogin/e2e_test/localserver"
"github.com/int128/kubelogin/pkg/adaptors/credentialplugin"
"github.com/int128/kubelogin/pkg/adaptors/credentialplugin/mock_credentialplugin"
"github.com/int128/kubelogin/pkg/adaptors/logger/mock_logger"
"github.com/int128/kubelogin/pkg/adaptors/tokencache"
"github.com/int128/kubelogin/pkg/di"
"github.com/int128/kubelogin/pkg/usecases/authentication"
)
// Run the integration tests of the credential plugin use-case.
//
// 1. Start the auth server.
// 2. Run the Cmd.
// 3. Open a request for the local server.
// 4. Verify the output.
//
func TestCredentialPlugin(t *testing.T) {
cacheDir, err := ioutil.TempDir("", "kube")
if err != nil {
t.Fatalf("could not create a cache dir: %s", err)
}
defer func() {
if err := os.RemoveAll(cacheDir); err != nil {
t.Errorf("could not clean up the cache dir: %s", err)
}
}()
t.Run("NoTLS", func(t *testing.T) {
testCredentialPlugin(t, cacheDir, keys.None, nil)
})
t.Run("TLS", func(t *testing.T) {
testCredentialPlugin(t, cacheDir, keys.Server, []string{"--certificate-authority", keys.Server.CACertPath})
})
}
func testCredentialPlugin(t *testing.T, cacheDir string, idpTLS keys.Keys, extraArgs []string) {
timeout := 1 * time.Second
t.Run("Defaults", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
service := mock_idp.NewMockService(ctrl)
serverURL, server := localserver.Start(t, idp.NewHandler(t, service), idpTLS)
defer server.Shutdown(t, ctx)
var idToken string
setupMockIDPForCodeFlow(t, service, serverURL, "openid", &idToken)
credentialPluginInteraction := mock_credentialplugin.NewMockInterface(ctrl)
assertCredentialPluginOutput(t, credentialPluginInteraction, &idToken)
args := []string{
"--token-cache-dir", cacheDir,
"--oidc-issuer-url", serverURL,
"--oidc-client-id", "kubernetes",
}
args = append(args, extraArgs...)
runGetTokenCmd(t, ctx, openBrowserOnReadyFunc(t, ctx, idpTLS), credentialPluginInteraction, args)
})
t.Run("ResourceOwnerPasswordCredentials", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
service := mock_idp.NewMockService(ctrl)
serverURL, server := localserver.Start(t, idp.NewHandler(t, service), idpTLS)
defer server.Shutdown(t, ctx)
idToken := newIDToken(t, serverURL, "", tokenExpiryFuture)
setupMockIDPForROPC(service, serverURL, "openid", "USER", "PASS", idToken)
credentialPluginInteraction := mock_credentialplugin.NewMockInterface(ctrl)
assertCredentialPluginOutput(t, credentialPluginInteraction, &idToken)
args := []string{
"--token-cache-dir", cacheDir,
"--oidc-issuer-url", serverURL,
"--oidc-client-id", "kubernetes",
"--username", "USER",
"--password", "PASS",
}
args = append(args, extraArgs...)
runGetTokenCmd(t, ctx, openBrowserOnReadyFunc(t, ctx, idpTLS), credentialPluginInteraction, args)
})
t.Run("HasValidToken", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
service := mock_idp.NewMockService(ctrl)
serverURL, server := localserver.Start(t, idp.NewHandler(t, service), idpTLS)
defer server.Shutdown(t, ctx)
idToken := newIDToken(t, serverURL, "YOUR_NONCE", tokenExpiryFuture)
setupTokenCache(t, cacheDir, tokencache.Key{
IssuerURL: serverURL,
ClientID: "kubernetes",
}, tokencache.TokenCache{
IDToken: idToken,
RefreshToken: "YOUR_REFRESH_TOKEN",
})
credentialPluginInteraction := mock_credentialplugin.NewMockInterface(ctrl)
assertCredentialPluginOutput(t, credentialPluginInteraction, &idToken)
args := []string{
"--token-cache-dir", cacheDir,
"--oidc-issuer-url", serverURL,
"--oidc-client-id", "kubernetes",
}
args = append(args, extraArgs...)
runGetTokenCmd(t, ctx, openBrowserOnReadyFunc(t, ctx, idpTLS), credentialPluginInteraction, args)
assertTokenCache(t, cacheDir, tokencache.Key{
IssuerURL: serverURL,
ClientID: "kubernetes",
}, tokencache.TokenCache{
IDToken: idToken,
RefreshToken: "YOUR_REFRESH_TOKEN",
})
})
t.Run("HasValidRefreshToken", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
service := mock_idp.NewMockService(ctrl)
serverURL, server := localserver.Start(t, idp.NewHandler(t, service), idpTLS)
defer server.Shutdown(t, ctx)
validIDToken := newIDToken(t, serverURL, "YOUR_NONCE", tokenExpiryFuture)
expiredIDToken := newIDToken(t, serverURL, "YOUR_NONCE", tokenExpiryPast)
setupMockIDPForDiscovery(service, serverURL)
service.EXPECT().Refresh("VALID_REFRESH_TOKEN").
Return(idp.NewTokenResponse(validIDToken, "NEW_REFRESH_TOKEN"), nil)
setupTokenCache(t, cacheDir, tokencache.Key{
IssuerURL: serverURL,
ClientID: "kubernetes",
}, tokencache.TokenCache{
IDToken: expiredIDToken,
RefreshToken: "VALID_REFRESH_TOKEN",
})
credentialPluginInteraction := mock_credentialplugin.NewMockInterface(ctrl)
assertCredentialPluginOutput(t, credentialPluginInteraction, &validIDToken)
args := []string{
"--token-cache-dir", cacheDir,
"--oidc-issuer-url", serverURL,
"--oidc-client-id", "kubernetes",
}
args = append(args, extraArgs...)
runGetTokenCmd(t, ctx, openBrowserOnReadyFunc(t, ctx, idpTLS), credentialPluginInteraction, args)
assertTokenCache(t, cacheDir, tokencache.Key{
IssuerURL: serverURL,
ClientID: "kubernetes",
}, tokencache.TokenCache{
IDToken: validIDToken,
RefreshToken: "NEW_REFRESH_TOKEN",
})
})
t.Run("HasExpiredRefreshToken", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
service := mock_idp.NewMockService(ctrl)
serverURL, server := localserver.Start(t, idp.NewHandler(t, service), idpTLS)
defer server.Shutdown(t, ctx)
validIDToken := newIDToken(t, serverURL, "YOUR_NONCE", tokenExpiryFuture)
expiredIDToken := newIDToken(t, serverURL, "YOUR_NONCE", tokenExpiryPast)
setupMockIDPForCodeFlow(t, service, serverURL, "openid", &validIDToken)
service.EXPECT().Refresh("EXPIRED_REFRESH_TOKEN").
Return(nil, &idp.ErrorResponse{Code: "invalid_request", Description: "token has expired"}).
MaxTimes(2) // package oauth2 will retry refreshing the token
setupTokenCache(t, cacheDir, tokencache.Key{
IssuerURL: serverURL,
ClientID: "kubernetes",
}, tokencache.TokenCache{
IDToken: expiredIDToken,
RefreshToken: "EXPIRED_REFRESH_TOKEN",
})
credentialPluginInteraction := mock_credentialplugin.NewMockInterface(ctrl)
assertCredentialPluginOutput(t, credentialPluginInteraction, &validIDToken)
args := []string{
"--token-cache-dir", cacheDir,
"--oidc-issuer-url", serverURL,
"--oidc-client-id", "kubernetes",
}
args = append(args, extraArgs...)
runGetTokenCmd(t, ctx, openBrowserOnReadyFunc(t, ctx, idpTLS), credentialPluginInteraction, args)
assertTokenCache(t, cacheDir, tokencache.Key{
IssuerURL: serverURL,
ClientID: "kubernetes",
}, tokencache.TokenCache{
IDToken: validIDToken,
RefreshToken: "YOUR_REFRESH_TOKEN",
})
})
t.Run("ExtraScopes", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
service := mock_idp.NewMockService(ctrl)
serverURL, server := localserver.Start(t, idp.NewHandler(t, service), idpTLS)
defer server.Shutdown(t, ctx)
var idToken string
setupMockIDPForCodeFlow(t, service, serverURL, "email profile openid", &idToken)
credentialPluginInteraction := mock_credentialplugin.NewMockInterface(ctrl)
assertCredentialPluginOutput(t, credentialPluginInteraction, &idToken)
args := []string{
"--token-cache-dir", cacheDir,
"--oidc-issuer-url", serverURL,
"--oidc-client-id", "kubernetes",
"--oidc-extra-scope", "email",
"--oidc-extra-scope", "profile",
}
args = append(args, extraArgs...)
runGetTokenCmd(t, ctx, openBrowserOnReadyFunc(t, ctx, idpTLS), credentialPluginInteraction, args)
})
}
func assertCredentialPluginOutput(t *testing.T, credentialPluginInteraction *mock_credentialplugin.MockInterface, idToken *string) {
credentialPluginInteraction.EXPECT().
Write(gomock.Any()).
Do(func(out credentialplugin.Output) {
if out.Token != *idToken {
t.Errorf("Token wants %s but %s", *idToken, out.Token)
}
if out.Expiry != tokenExpiryFuture {
t.Errorf("Expiry wants %v but %v", tokenExpiryFuture, out.Expiry)
}
})
}
func runGetTokenCmd(t *testing.T, ctx context.Context, localServerReadyFunc authentication.LocalServerReadyFunc, interaction credentialplugin.Interface, args []string) {
t.Helper()
cmd := di.NewCmdForHeadless(mock_logger.New(t), localServerReadyFunc, interaction)
exitCode := cmd.Run(ctx, append([]string{
"kubelogin", "get-token",
"--v=1",
"--skip-open-browser",
"--listen-port", "0",
}, args...), "HEAD")
if exitCode != 0 {
t.Errorf("exit status wants 0 but %d", exitCode)
}
}
func setupTokenCache(t *testing.T, cacheDir string, k tokencache.Key, v tokencache.TokenCache) {
var r tokencache.Repository
err := r.Save(cacheDir, k, v)
if err != nil {
t.Errorf("could not set up the token cache: %s", err)
}
}
func assertTokenCache(t *testing.T, cacheDir string, k tokencache.Key, want tokencache.TokenCache) {
var r tokencache.Repository
v, err := r.FindByKey(cacheDir, k)
if err != nil {
t.Errorf("could not set up the token cache: %s", err)
}
if diff := cmp.Diff(&want, v); diff != "" {
t.Errorf("token cache mismatch: %s", diff)
}
}

View File

@@ -1,91 +0,0 @@
package e2e_test
import (
"context"
"net/http"
"testing"
"time"
"github.com/dgrijalva/jwt-go"
"github.com/golang/mock/gomock"
"github.com/int128/kubelogin/e2e_test/idp"
"github.com/int128/kubelogin/e2e_test/idp/mock_idp"
"github.com/int128/kubelogin/e2e_test/keys"
"github.com/int128/kubelogin/pkg/usecases/authentication"
)
var (
tokenExpiryFuture = time.Now().Add(time.Hour).Round(time.Second)
tokenExpiryPast = time.Now().Add(-time.Hour).Round(time.Second)
)
func newIDToken(t *testing.T, issuer, nonce string, expiry time.Time) string {
t.Helper()
var claims struct {
jwt.StandardClaims
Nonce string `json:"nonce"`
Groups []string `json:"groups"`
}
claims.StandardClaims = jwt.StandardClaims{
Issuer: issuer,
Audience: "kubernetes",
Subject: "SUBJECT",
IssuedAt: time.Now().Unix(),
ExpiresAt: expiry.Unix(),
}
claims.Nonce = nonce
claims.Groups = []string{"admin", "users"}
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
s, err := token.SignedString(keys.JWSKeyPair)
if err != nil {
t.Fatalf("Could not sign the claims: %s", err)
}
return s
}
func setupMockIDPForDiscovery(service *mock_idp.MockService, serverURL string) {
service.EXPECT().Discovery().Return(idp.NewDiscoveryResponse(serverURL))
service.EXPECT().GetCertificates().Return(idp.NewCertificatesResponse(keys.JWSKeyPair))
}
func setupMockIDPForCodeFlow(t *testing.T, service *mock_idp.MockService, serverURL, scope string, idToken *string) {
var nonce string
setupMockIDPForDiscovery(service, serverURL)
service.EXPECT().AuthenticateCode(scope, gomock.Any()).
DoAndReturn(func(_, gotNonce string) (string, error) {
nonce = gotNonce
return "YOUR_AUTH_CODE", nil
})
service.EXPECT().Exchange("YOUR_AUTH_CODE").
DoAndReturn(func(string) (*idp.TokenResponse, error) {
*idToken = newIDToken(t, serverURL, nonce, tokenExpiryFuture)
return idp.NewTokenResponse(*idToken, "YOUR_REFRESH_TOKEN"), nil
})
}
func setupMockIDPForROPC(service *mock_idp.MockService, serverURL, scope, username, password, idToken string) {
setupMockIDPForDiscovery(service, serverURL)
service.EXPECT().AuthenticatePassword(username, password, scope).
Return(idp.NewTokenResponse(idToken, "YOUR_REFRESH_TOKEN"), nil)
}
func openBrowserOnReadyFunc(t *testing.T, ctx context.Context, k keys.Keys) authentication.LocalServerReadyFunc {
return func(url string) {
client := http.Client{Transport: &http.Transport{TLSClientConfig: k.TLSConfig}}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
t.Errorf("could not create a request: %s", err)
return
}
req = req.WithContext(ctx)
resp, err := client.Do(req)
if err != nil {
t.Errorf("could not send a request: %s", err)
return
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
t.Errorf("StatusCode wants 200 but %d", resp.StatusCode)
}
}
}

View File

@@ -1,122 +0,0 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/int128/kubelogin/e2e_test/idp (interfaces: Service)
// Package mock_idp is a generated GoMock package.
package mock_idp
import (
gomock "github.com/golang/mock/gomock"
idp "github.com/int128/kubelogin/e2e_test/idp"
reflect "reflect"
)
// MockService is a mock of Service interface
type MockService struct {
ctrl *gomock.Controller
recorder *MockServiceMockRecorder
}
// MockServiceMockRecorder is the mock recorder for MockService
type MockServiceMockRecorder struct {
mock *MockService
}
// NewMockService creates a new mock instance
func NewMockService(ctrl *gomock.Controller) *MockService {
mock := &MockService{ctrl: ctrl}
mock.recorder = &MockServiceMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockService) EXPECT() *MockServiceMockRecorder {
return m.recorder
}
// AuthenticateCode mocks base method
func (m *MockService) AuthenticateCode(arg0, arg1 string) (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AuthenticateCode", arg0, arg1)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AuthenticateCode indicates an expected call of AuthenticateCode
func (mr *MockServiceMockRecorder) AuthenticateCode(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthenticateCode", reflect.TypeOf((*MockService)(nil).AuthenticateCode), arg0, arg1)
}
// AuthenticatePassword mocks base method
func (m *MockService) AuthenticatePassword(arg0, arg1, arg2 string) (*idp.TokenResponse, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AuthenticatePassword", arg0, arg1, arg2)
ret0, _ := ret[0].(*idp.TokenResponse)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// AuthenticatePassword indicates an expected call of AuthenticatePassword
func (mr *MockServiceMockRecorder) AuthenticatePassword(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AuthenticatePassword", reflect.TypeOf((*MockService)(nil).AuthenticatePassword), arg0, arg1, arg2)
}
// Discovery mocks base method
func (m *MockService) Discovery() *idp.DiscoveryResponse {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Discovery")
ret0, _ := ret[0].(*idp.DiscoveryResponse)
return ret0
}
// Discovery indicates an expected call of Discovery
func (mr *MockServiceMockRecorder) Discovery() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Discovery", reflect.TypeOf((*MockService)(nil).Discovery))
}
// Exchange mocks base method
func (m *MockService) Exchange(arg0 string) (*idp.TokenResponse, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Exchange", arg0)
ret0, _ := ret[0].(*idp.TokenResponse)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Exchange indicates an expected call of Exchange
func (mr *MockServiceMockRecorder) Exchange(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exchange", reflect.TypeOf((*MockService)(nil).Exchange), arg0)
}
// GetCertificates mocks base method
func (m *MockService) GetCertificates() *idp.CertificatesResponse {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetCertificates")
ret0, _ := ret[0].(*idp.CertificatesResponse)
return ret0
}
// GetCertificates indicates an expected call of GetCertificates
func (mr *MockServiceMockRecorder) GetCertificates() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCertificates", reflect.TypeOf((*MockService)(nil).GetCertificates))
}
// Refresh mocks base method
func (m *MockService) Refresh(arg0 string) (*idp.TokenResponse, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Refresh", arg0)
ret0, _ := ret[0].(*idp.TokenResponse)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Refresh indicates an expected call of Refresh
func (mr *MockServiceMockRecorder) Refresh(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Refresh", reflect.TypeOf((*MockService)(nil).Refresh), arg0)
}

View File

@@ -1,67 +0,0 @@
package keys
import (
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"encoding/pem"
"io/ioutil"
)
// Keys represents a pair of certificate and key.
type Keys struct {
CertPath string
KeyPath string
CACertPath string
TLSConfig *tls.Config
}
// None represents non-TLS.
var None Keys
// Server is a Keys for TLS server.
// These files should be generated by Makefile before test.
var Server = Keys{
CertPath: "keys/testdata/server.crt",
KeyPath: "keys/testdata/server.key",
CACertPath: "keys/testdata/ca.crt",
TLSConfig: newTLSConfig("keys/testdata/ca.crt"),
}
// JWSKey is path to the key for signing ID tokens.
// This file should be generated by Makefile before test.
const JWSKey = "keys/testdata/jws.key"
// JWSKeyPair is the key pair loaded from JWSKey.
var JWSKeyPair = readPrivateKey(JWSKey)
func newTLSConfig(name string) *tls.Config {
b, err := ioutil.ReadFile(name)
if err != nil {
panic(err)
}
p := x509.NewCertPool()
if !p.AppendCertsFromPEM(b) {
panic("could not append the CA cert")
}
return &tls.Config{RootCAs: p}
}
func readPrivateKey(name string) *rsa.PrivateKey {
b, err := ioutil.ReadFile(name)
if err != nil {
panic(err)
}
block, rest := pem.Decode(b)
if block == nil {
panic("could not decode PEM")
}
if len(rest) > 0 {
panic("PEM should contain single key but multiple keys")
}
k, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
panic(err)
}
return k
}

View File

@@ -1 +0,0 @@
/CA

View File

@@ -1,59 +0,0 @@
EXPIRY := 3650
all: ca.key ca.crt server.key server.crt jws.key
.PHONY: clean
clean:
-rm -v ca.* server.* jws.*
ca.key:
openssl genrsa -out $@ 1024
.INTERMEDIATE: ca.csr
ca.csr: openssl.cnf ca.key
openssl req -config openssl.cnf \
-new \
-key ca.key \
-subj "/CN=Hello CA" \
-out $@
openssl req -noout -text -in $@
ca.crt: ca.csr ca.key
openssl x509 \
-req \
-days $(EXPIRY) \
-signkey ca.key \
-in ca.csr \
-out $@
openssl x509 -text -in $@
server.key:
openssl genrsa -out $@ 1024
.INTERMEDIATE: server.csr
server.csr: openssl.cnf server.key
openssl req -config openssl.cnf \
-new \
-key server.key \
-subj "/CN=localhost" \
-out $@
openssl req -noout -text -in $@
server.crt: openssl.cnf server.csr ca.key ca.crt
rm -fr ./CA
mkdir -p ./CA
touch CA/index.txt
touch CA/index.txt.attr
echo 00 > CA/serial
openssl ca -config openssl.cnf \
-days $(EXPIRY) \
-extensions v3_req \
-batch \
-cert ca.crt \
-keyfile ca.key \
-in server.csr \
-out $@
openssl x509 -text -in $@
jws.key:
openssl genrsa -out $@ 1024

View File

@@ -1,11 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIBnTCCAQYCCQC/aR7GRyndljANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDDAhI
ZWxsbyBDQTAeFw0xOTA5MjUxNDQ0NTFaFw0yOTA5MjIxNDQ0NTFaMBMxETAPBgNV
BAMMCEhlbGxvIENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDnSTDsRx4U
JmaTWHOAZasfN2O37wMcRez7LDM2qfQ8nlXnEAAZ4Pc51itOycWN1nclNVb489i9
J8ALgRKzNumSkfl1sCgJoDds75AC3oRRCbhnEP3Lu4mysxyOtYZNsdST8GBCP0m4
2tWa4W2ditpA44uU4x8opAX2qY919nVLNwIDAQABMA0GCSqGSIb3DQEBBQUAA4GB
AE/gsgTC4jzYC3icZdhALJTe3JsZ7geN702dE95zSI5LXAzzHJ/j8wGmorQjrMs2
iNPjVOdTU6cVWa1Ba29wWakVyVCUqDmDiWHaVhM/Qyyxo6mVlZGFwSnto3zq/h4y
KMFJ8lUtFCYMrzo5wqgj2xOjVrN77F6F4XWZbMufh50G
-----END CERTIFICATE-----

View File

@@ -1,15 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDnSTDsRx4UJmaTWHOAZasfN2O37wMcRez7LDM2qfQ8nlXnEAAZ
4Pc51itOycWN1nclNVb489i9J8ALgRKzNumSkfl1sCgJoDds75AC3oRRCbhnEP3L
u4mysxyOtYZNsdST8GBCP0m42tWa4W2ditpA44uU4x8opAX2qY919nVLNwIDAQAB
AoGAaYmTYm29QvKW4et9oPxDjpYG0bqlz7P0xFRR9kKtKTATAMHjWeu2xFR/JI+b
rvJLIdZqHmWe5AmMb3NxZgfLonEB71ohaKQha1L8Vc7aoedRheJvqqaNr+ZxoCMO
8xcjsaMYxLEVt0tg6XyKyEhi1/hOufFZ4BSng4oQbrpaNIkCQQD6hPEzzPZtMEEe
eRdwTVUIStKFMQbRdwZ5Oc7pyDk2U+SFRJiqkBkqnmFekcf2UgbBQxem+GMhWNgE
LItKy/wVAkEA7FiHxbzn2msaE3hZCWudtnXqmJNuPO0zJ5icXe2svwmwPfLA/rm9
iazCuyzyK67J8IG9QgIjQFYXtQbMr2chGwJBAMm3dghBx0LQEf8Zfdf9TLSqmqyI
d3b+IgZGl+cCQ58NGfp863ibIsiAUuK0+4/JKItBHLBjXF6jjPx/aYFGkqkCQH4w
GnXCEYx1qJuCow87jR4xQQsrlC0lfC2E9t/TmWr6UkYRCWg3ZXJPcj0bl0Upcppd
ut22ZHniPZAizEBOcMcCQQDnMEOxufxhMsx2NC8yON/noewLINqKcbkMsl6DjvJl
+wLbQmzJ0j+uIBgdpsj4rWnEr7GxoL2eWG44QDUBco79
-----END RSA PRIVATE KEY-----

View File

@@ -1,15 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXwIBAAKBgQCZukkN1GxMlNXkpOZxCnvCF874/rn1sNKzO98fOwmBRPG2+m/c
yqBY7t2L2nihqz3+GZTiHmzSrBzMAGPVW1qGmk9KYg3m7akz9SiCxdoUkgM9MCCp
X/s8IhgtXkyoKFPcGdwHblDl/3aJG02b6TAQD8vTNQAKoKw7L0FST+pvRwIDAQAB
AoGBAJT1fXR5MbfDQL+dSe6fSex5RYTgzzDTdldW3I1Wl487Tz0OzvYTIe0LCIJL
4DhHxnpCL5IsCSbav8ytVA+ZxczHpEW6UxbalXt5UfgFu0joTrdoGxDcVWgUCW3J
Olbln0lOP55wViKh509gt45Za3VxJrNul3khVfVj7qGG9cKBAkEAxwtT8LxwqTYF
nqoeZvPp15JAqlgdk38ttJa4KEqvpBTSxNIXkL9T5gJ+irKZAzxlz/U7bhn5mw6E
3xFiljOXpQJBAMW3XRFOjgNBXNjbt81wREF5LdZl9EI8cRMSH6xljt2uwSqw4EG3
76gFvccUd+WnfspFQZVypSSD4pWzsAqh13sCQQCA9BLW5Y7r4ab0a2y08JNwaT1h
3yKSO5QF6pu25uQyHpeKkj5YNcyKONV40EqXsRqZB10QcN2omlh1GJNRkm1NAkEA
qV3lr4mnRUqcinfM/4MINT3k8h/sGUFFa5y+3SMyOtwURMm3kRRLi5c/dmYmPug4
SHUDNU48AQeo9awzRShWOQJBAJdw+cfRgi4fo3HY33uZdFa1T9G+qTA2ijhco6O3
8tOc0yOFEtPNXM87MsHGIQP3ZCLfIY1gs2O3WCTFbPxR4rc=
-----END RSA PRIVATE KEY-----

View File

@@ -1,36 +0,0 @@
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = ./CA
certs = $dir
crl_dir = $dir
database = $dir/index.txt
new_certs_dir = $dir
default_md = sha256
policy = policy_match
serial = $dir/serial
[ policy_match ]
countryName = optional
stateOrProvinceName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
distinguished_name = req_distinguished_name
req_extensions = v3_req
x509_extensions = v3_ca
[ req_distinguished_name ]
commonName = Common Name (e.g. server FQDN or YOUR name)
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = DNS:localhost
[ v3_ca ]
basicConstraints = CA:true

View File

@@ -1,52 +0,0 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 0 (0x0)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=Hello CA
Validity
Not Before: Aug 18 06:00:06 2019 GMT
Not After : Aug 15 06:00:06 2029 GMT
Subject: CN=localhost
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (1024 bit)
Modulus:
00:d6:4e:eb:3a:cb:25:f9:7e:92:22:f2:63:99:da:
08:05:8b:a3:e7:d3:fd:71:3e:bd:da:c5:d5:63:b7:
d3:7b:f8:cd:1a:2e:5c:a2:4f:48:98:c2:b4:da:e8:
1e:d3:d7:8f:d8:ee:a9:70:d0:9d:4f:f4:8d:95:e5:
8e:9a:71:b6:80:aa:0b:cb:28:1d:f6:0d:7e:aa:78:
bf:30:e6:58:d7:6b:92:8f:19:1c:7d:95:f8:d5:2f:
8c:58:49:98:88:05:50:88:80:a9:77:c4:16:b4:c1:
00:45:1e:d3:d0:ed:98:4d:f7:a3:5d:f1:82:cb:a5:
4d:19:64:4d:43:db:13:d4:17
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Basic Constraints:
CA:FALSE
X509v3 Key Usage:
Digital Signature, Non Repudiation, Key Encipherment
X509v3 Subject Alternative Name:
DNS:localhost
Signature Algorithm: sha256WithRSAEncryption
5a:5c:5e:8b:de:82:86:f4:98:40:0e:cf:c5:51:fe:89:46:49:
f0:26:d2:a5:06:e3:91:43:c1:f8:b2:ad:b7:a1:23:13:1a:80:
45:00:51:70:b6:06:63:c6:a8:c8:22:5d:1b:00:e0:4a:8c:2e:
ce:b4:da:b1:89:8a:d2:d0:e3:eb:0f:16:34:45:a1:bd:64:5c:
48:41:8c:0a:bf:66:be:1c:a8:35:47:ce:b0:dc:c8:4f:5e:c1:
ec:ef:21:fb:45:55:95:e3:99:40:46:0b:6c:8a:b3:d5:f0:bf:
39:a4:ba:c4:d7:58:88:58:08:07:98:59:6e:ca:9c:08:e4:c4:
4f:db
-----BEGIN CERTIFICATE-----
MIIBzTCCATagAwIBAgIBADANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhIZWxs
byBDQTAeFw0xOTA4MTgwNjAwMDZaFw0yOTA4MTUwNjAwMDZaMBQxEjAQBgNVBAMM
CWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1k7rOssl+X6S
IvJjmdoIBYuj59P9cT692sXVY7fTe/jNGi5cok9ImMK02uge09eP2O6pcNCdT/SN
leWOmnG2gKoLyygd9g1+qni/MOZY12uSjxkcfZX41S+MWEmYiAVQiICpd8QWtMEA
RR7T0O2YTfejXfGCy6VNGWRNQ9sT1BcCAwEAAaMwMC4wCQYDVR0TBAIwADALBgNV
HQ8EBAMCBeAwFAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBCwUAA4GB
AFpcXovegob0mEAOz8VR/olGSfAm0qUG45FDwfiyrbehIxMagEUAUXC2BmPGqMgi
XRsA4EqMLs602rGJitLQ4+sPFjRFob1kXEhBjAq/Zr4cqDVHzrDcyE9ewezvIftF
VZXjmUBGC2yKs9XwvzmkusTXWIhYCAeYWW7KnAjkxE/b
-----END CERTIFICATE-----

View File

@@ -1,15 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDWTus6yyX5fpIi8mOZ2ggFi6Pn0/1xPr3axdVjt9N7+M0aLlyi
T0iYwrTa6B7T14/Y7qlw0J1P9I2V5Y6acbaAqgvLKB32DX6qeL8w5ljXa5KPGRx9
lfjVL4xYSZiIBVCIgKl3xBa0wQBFHtPQ7ZhN96Nd8YLLpU0ZZE1D2xPUFwIDAQAB
AoGBAJhNR7Dl1JwFzndViWE6aP7/6UEFEBWeADDs7aTLbFmrTJ+xmRWkgLRHk14L
HnVwuYLywaoyJ8o9wy1nEbxC2e4zWZ94d351MQf3/komCXDBzEsktfAcNsAFnMmS
HZuGXfhi0FYWoftpIGxUmEBmQRcq0ctycbLves6TY3y+oajpAkEA8UHmSr/zsM3E
XQXPp2BCAvRrTH/njk4R0jwB29Bi89gt/XDD4uvfWbHw7TZxnZuCpWisnxpMPIwa
1rjqIQmhEwJBAONncQUOxwYCIuvraIhV0QtkIUa+YpTvAxP8ZNXx+agtHmHG2TTf
kGv2YddvjxXZItN/FZOzUGm9OptaeLRTpW0CQHO8CEzNnoqve0agtgf2LlSaiiqt
pRhoLTZsYPvhEMcnapCNGvtt6bxul0REfOZ9poPRHhZJGE9naqydEnv80Y8CQQC3
pxLfws95SsBpR/VkJepuCK/XMmrrXRxfR7coEgROjiG7VZyV1vgMOS9Ljg1A19wI
cto6LtcCjpCGZsqU1/kBAkEAv2tXBts3vuIjguZNMz7KLWmu3zG2SQRaqdEZwL+R
DQmD5tbI6gEtd5OmgmSiW8A4mpfgFYvG7Um2fwi7TTXtSA==
-----END RSA PRIVATE KEY-----

View File

@@ -1,85 +0,0 @@
// Package localserver provides a http server running on localhost.
// This is only for testing.
//
package localserver
import (
"context"
"net"
"net/http"
"testing"
"github.com/int128/kubelogin/e2e_test/keys"
)
type Shutdowner interface {
Shutdown(t *testing.T, ctx context.Context)
}
type shutdowner struct {
l net.Listener
s *http.Server
}
func (s *shutdowner) Shutdown(t *testing.T, ctx context.Context) {
// s.Shutdown() closes the lister as well,
// so we do not need to call l.Close() explicitly
if err := s.s.Shutdown(ctx); err != nil {
t.Errorf("Could not shutdown the server: %s", err)
}
}
// Start starts an authentication server.
// If k is non-nil, it starts a TLS server.
func Start(t *testing.T, h http.Handler, k keys.Keys) (string, Shutdowner) {
if k == keys.None {
return startNoTLS(t, h)
}
return startTLS(t, h, k)
}
func startNoTLS(t *testing.T, h http.Handler) (string, Shutdowner) {
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)
}
}()
return url, &shutdowner{l, s}
}
func startTLS(t *testing.T, h http.Handler, k keys.Keys) (string, Shutdowner) {
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)
}
}()
return url, &shutdowner{l, s}
}
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

@@ -1,283 +0,0 @@
package e2e_test
import (
"context"
"os"
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/int128/kubelogin/e2e_test/idp"
"github.com/int128/kubelogin/e2e_test/idp/mock_idp"
"github.com/int128/kubelogin/e2e_test/keys"
"github.com/int128/kubelogin/e2e_test/kubeconfig"
"github.com/int128/kubelogin/e2e_test/localserver"
"github.com/int128/kubelogin/pkg/adaptors/logger/mock_logger"
"github.com/int128/kubelogin/pkg/di"
"github.com/int128/kubelogin/pkg/usecases/authentication"
)
// Run the integration tests of the Login use-case.
//
// 1. Start the auth server.
// 2. Run the Cmd.
// 3. Open a request for the local server.
// 4. Verify the kubeconfig.
//
func TestStandalone(t *testing.T) {
t.Run("NoTLS", func(t *testing.T) {
testStandalone(t, keys.None)
})
t.Run("TLS", func(t *testing.T) {
testStandalone(t, keys.Server)
})
}
func testStandalone(t *testing.T, idpTLS keys.Keys) {
timeout := 5 * time.Second
t.Run("Defaults", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
service := mock_idp.NewMockService(ctrl)
serverURL, server := localserver.Start(t, idp.NewHandler(t, service), idpTLS)
defer server.Shutdown(t, ctx)
var idToken string
setupMockIDPForCodeFlow(t, service, serverURL, "openid", &idToken)
kubeConfigFilename := kubeconfig.Create(t, &kubeconfig.Values{
Issuer: serverURL,
IDPCertificateAuthority: idpTLS.CACertPath,
})
defer os.Remove(kubeConfigFilename)
args := []string{
"--kubeconfig", kubeConfigFilename,
}
runRootCmd(t, ctx, openBrowserOnReadyFunc(t, ctx, idpTLS), args)
kubeconfig.Verify(t, kubeConfigFilename, kubeconfig.AuthProviderConfig{
IDToken: idToken,
RefreshToken: "YOUR_REFRESH_TOKEN",
})
})
t.Run("ResourceOwnerPasswordCredentials", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
service := mock_idp.NewMockService(ctrl)
serverURL, server := localserver.Start(t, idp.NewHandler(t, service), idpTLS)
defer server.Shutdown(t, ctx)
idToken := newIDToken(t, serverURL, "", tokenExpiryFuture)
setupMockIDPForROPC(service, serverURL, "openid", "USER", "PASS", idToken)
kubeConfigFilename := kubeconfig.Create(t, &kubeconfig.Values{
Issuer: serverURL,
IDPCertificateAuthority: idpTLS.CACertPath,
})
defer os.Remove(kubeConfigFilename)
args := []string{
"--kubeconfig", kubeConfigFilename,
"--username", "USER",
"--password", "PASS",
}
runRootCmd(t, ctx, openBrowserOnReadyFunc(t, ctx, idpTLS), args)
kubeconfig.Verify(t, kubeConfigFilename, kubeconfig.AuthProviderConfig{
IDToken: idToken,
RefreshToken: "YOUR_REFRESH_TOKEN",
})
})
t.Run("HasValidToken", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
service := mock_idp.NewMockService(ctrl)
serverURL, server := localserver.Start(t, idp.NewHandler(t, service), idpTLS)
defer server.Shutdown(t, ctx)
idToken := newIDToken(t, serverURL, "YOUR_NONCE", tokenExpiryFuture)
kubeConfigFilename := kubeconfig.Create(t, &kubeconfig.Values{
Issuer: serverURL,
IDToken: idToken,
RefreshToken: "YOUR_REFRESH_TOKEN",
IDPCertificateAuthority: idpTLS.CACertPath,
})
defer os.Remove(kubeConfigFilename)
args := []string{
"--kubeconfig", kubeConfigFilename,
}
runRootCmd(t, ctx, openBrowserOnReadyFunc(t, ctx, idpTLS), args)
kubeconfig.Verify(t, kubeConfigFilename, kubeconfig.AuthProviderConfig{
IDToken: idToken,
RefreshToken: "YOUR_REFRESH_TOKEN",
})
})
t.Run("HasValidRefreshToken", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
service := mock_idp.NewMockService(ctrl)
serverURL, server := localserver.Start(t, idp.NewHandler(t, service), idpTLS)
defer server.Shutdown(t, ctx)
idToken := newIDToken(t, serverURL, "YOUR_NONCE", tokenExpiryFuture)
service.EXPECT().Discovery().Return(idp.NewDiscoveryResponse(serverURL))
service.EXPECT().GetCertificates().Return(idp.NewCertificatesResponse(keys.JWSKeyPair))
service.EXPECT().Refresh("VALID_REFRESH_TOKEN").
Return(idp.NewTokenResponse(idToken, "NEW_REFRESH_TOKEN"), nil)
kubeConfigFilename := kubeconfig.Create(t, &kubeconfig.Values{
Issuer: serverURL,
IDToken: newIDToken(t, serverURL, "YOUR_NONCE", tokenExpiryPast), // expired
RefreshToken: "VALID_REFRESH_TOKEN",
IDPCertificateAuthority: idpTLS.CACertPath,
})
defer os.Remove(kubeConfigFilename)
args := []string{
"--kubeconfig", kubeConfigFilename,
}
runRootCmd(t, ctx, openBrowserOnReadyFunc(t, ctx, idpTLS), args)
kubeconfig.Verify(t, kubeConfigFilename, kubeconfig.AuthProviderConfig{
IDToken: idToken,
RefreshToken: "NEW_REFRESH_TOKEN",
})
})
t.Run("HasExpiredRefreshToken", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
service := mock_idp.NewMockService(ctrl)
serverURL, server := localserver.Start(t, idp.NewHandler(t, service), idpTLS)
defer server.Shutdown(t, ctx)
var idToken string
setupMockIDPForCodeFlow(t, service, serverURL, "openid", &idToken)
service.EXPECT().Refresh("EXPIRED_REFRESH_TOKEN").
Return(nil, &idp.ErrorResponse{Code: "invalid_request", Description: "token has expired"}).
MaxTimes(2) // package oauth2 will retry refreshing the token
kubeConfigFilename := kubeconfig.Create(t, &kubeconfig.Values{
Issuer: serverURL,
IDToken: newIDToken(t, serverURL, "YOUR_NONCE", tokenExpiryPast), // expired
RefreshToken: "EXPIRED_REFRESH_TOKEN",
IDPCertificateAuthority: idpTLS.CACertPath,
})
defer os.Remove(kubeConfigFilename)
args := []string{
"--kubeconfig", kubeConfigFilename,
}
runRootCmd(t, ctx, openBrowserOnReadyFunc(t, ctx, idpTLS), args)
kubeconfig.Verify(t, kubeConfigFilename, kubeconfig.AuthProviderConfig{
IDToken: idToken,
RefreshToken: "YOUR_REFRESH_TOKEN",
})
})
t.Run("env_KUBECONFIG", func(t *testing.T) {
// do not run this in parallel due to change of the env var
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
service := mock_idp.NewMockService(ctrl)
serverURL, server := localserver.Start(t, idp.NewHandler(t, service), idpTLS)
defer server.Shutdown(t, ctx)
var idToken string
setupMockIDPForCodeFlow(t, service, serverURL, "openid", &idToken)
kubeConfigFilename := kubeconfig.Create(t, &kubeconfig.Values{
Issuer: serverURL,
IDPCertificateAuthority: idpTLS.CACertPath,
})
defer os.Remove(kubeConfigFilename)
setenv(t, "KUBECONFIG", kubeConfigFilename+string(os.PathListSeparator)+"kubeconfig/testdata/dummy.yaml")
defer unsetenv(t, "KUBECONFIG")
args := []string{
"--kubeconfig", kubeConfigFilename,
}
runRootCmd(t, ctx, openBrowserOnReadyFunc(t, ctx, idpTLS), args)
kubeconfig.Verify(t, kubeConfigFilename, kubeconfig.AuthProviderConfig{
IDToken: idToken,
RefreshToken: "YOUR_REFRESH_TOKEN",
})
})
t.Run("ExtraScopes", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
service := mock_idp.NewMockService(ctrl)
serverURL, server := localserver.Start(t, idp.NewHandler(t, service), idpTLS)
defer server.Shutdown(t, ctx)
var idToken string
setupMockIDPForCodeFlow(t, service, serverURL, "profile groups openid", &idToken)
kubeConfigFilename := kubeconfig.Create(t, &kubeconfig.Values{
Issuer: serverURL,
ExtraScopes: "profile,groups",
IDPCertificateAuthority: idpTLS.CACertPath,
})
defer os.Remove(kubeConfigFilename)
args := []string{
"--kubeconfig", kubeConfigFilename,
}
runRootCmd(t, ctx, openBrowserOnReadyFunc(t, ctx, idpTLS), args)
kubeconfig.Verify(t, kubeConfigFilename, kubeconfig.AuthProviderConfig{
IDToken: idToken,
RefreshToken: "YOUR_REFRESH_TOKEN",
})
})
}
func runRootCmd(t *testing.T, ctx context.Context, localServerReadyFunc authentication.LocalServerReadyFunc, args []string) {
t.Helper()
cmd := di.NewCmdForHeadless(mock_logger.New(t), localServerReadyFunc, nil)
exitCode := cmd.Run(ctx, append([]string{
"kubelogin",
"--v=1",
"--listen-port", "0",
"--skip-open-browser",
}, args...), "HEAD")
if exitCode != 0 {
t.Errorf("exit status wants 0 but %d", exitCode)
}
}
func setenv(t *testing.T, key, value string) {
t.Helper()
if err := os.Setenv(key, value); err != nil {
t.Fatalf("Could not set the env var %s=%s: %s", key, value, err)
}
}
func unsetenv(t *testing.T, key string) {
t.Helper()
if err := os.Unsetenv(key); err != nil {
t.Fatalf("Could not unset the env var %s: %s", key, err)
}
}

73
go.mod
View File

@@ -1,26 +1,59 @@
module github.com/int128/kubelogin
go 1.12
go 1.22.2
require (
github.com/coreos/go-oidc v2.1.0+incompatible
github.com/dgrijalva/jwt-go v0.0.0-20160705203006-01aeca54ebda
github.com/go-test/deep v1.0.4
github.com/golang/mock v1.3.1
github.com/google/go-cmp v0.3.1
github.com/google/wire v0.4.0
github.com/int128/oauth2cli v1.8.1
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
github.com/spf13/cobra v0.0.5
github.com/alexflint/go-filemutex v1.3.0
github.com/chromedp/chromedp v0.10.0
github.com/coreos/go-oidc/v3 v3.11.0
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/oauth2dev v1.0.1
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7
gopkg.in/square/go-jose.v2 v2.3.1 // indirect
gopkg.in/yaml.v2 v2.2.7
k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719
k8s.io/client-go v0.0.0-20190620085101-78d2af792bab
k8s.io/klog v0.4.0
github.com/stretchr/testify v1.9.0
golang.org/x/oauth2 v0.21.0
golang.org/x/sync v0.7.0
golang.org/x/term v0.22.0
gopkg.in/yaml.v2 v2.4.0
k8s.io/apimachinery v0.30.3
k8s.io/client-go v0.30.3
k8s.io/klog/v2 v2.130.1
)
require (
github.com/chromedp/cdproto v0.0.0-20240801214329-3f85d328b335 // 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.2 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // 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/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/stretchr/objx v0.5.2 // indirect
golang.org/x/crypto v0.25.0 // indirect
golang.org/x/net v0.27.0 // indirect
golang.org/x/sys v0.22.0 // indirect
golang.org/x/text v0.16.0 // indirect
golang.org/x/time v0.3.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
)

653
go.sum
View File

@@ -1,175 +1,548 @@
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=
github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
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/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom8DBE9so9EBsM=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
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-20240801214329-3f85d328b335 h1:bATMoZLH2QGct1kzDxfmeBUQI/QhQvB0mBrOTct+YlQ=
github.com/chromedp/cdproto v0.0.0-20240801214329-3f85d328b335/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
github.com/chromedp/chromedp v0.10.0 h1:bRclRYVpMm/UVD76+1HcRW9eV3l58rFfy7AdBvKab1E=
github.com/chromedp/chromedp v0.10.0/go.mod h1:ei/1ncZIqXX1YnAYDkxhD4gzBgavMEUu7JCKvztdomE=
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.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/OtI=
github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
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/dgrijalva/jwt-go v0.0.0-20160705203006-01aeca54ebda h1:NyywMz59neOoVRFDz+ccfKWxn784fiHMDnZSy6T+JXY=
github.com/dgrijalva/jwt-go v0.0.0-20160705203006-01aeca54ebda/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho=
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415 h1:WSBJMqJbLxsn+bTCPyPYZfqHdJmc8MK4wrBjMft6BAM=
github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
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.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.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/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/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.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs=
github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc=
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/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
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/google/btree v0.0.0-20160524151835-7d79101e329e/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
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 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/wire v0.3.0 h1:imGQZGEVEHpje5056+K+cgdO72p0LQv2xIIFXNGUf60=
github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s=
github.com/google/wire v0.4.0 h1:kXcsA/rIGzJImVqPdhfnr6q0xsS9gU0515q1EPpJ9fE=
github.com/google/wire v0.4.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/gophercloud/gophercloud v0.0.0-20190126172459-c818fa66e4c8/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4=
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
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/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/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/int128/listener v1.0.0 h1:a9H3m4jbXgXpxJUK3fxWrh37Iic/UU/kYOGE0WtjbbI=
github.com/int128/listener v1.0.0/go.mod h1:sho0rrH7mNRRZH4hYOYx+xwRDGmtRndaUiu2z9iumes=
github.com/int128/oauth2cli v1.7.0 h1:lguQEIJ4IcSFRTqQ6y7avnfvPqVe0U6dlkW8mC1Epts=
github.com/int128/oauth2cli v1.7.0/go.mod h1:bucNn0/es9IhOf0a2MWPvJ5xO5f6JYrCfitQTyjI5lA=
github.com/int128/oauth2cli v1.8.1 h1:Vkmfx0w225l4qUpJ1ZWGw1elw7hnXAybSiYoYyh1iBw=
github.com/int128/oauth2cli v1.8.1/go.mod h1:MkxKWhHUaPOaq/92Z5ifdCWySAKJKo04hUXaKA7OgDE=
github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be h1:AHimNtVIpiBjPUhEF5KNCkrUyqTSA5zWUl8sQ2bfGBE=
github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
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/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/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=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 h1:49lOXmGaUpV9Fz3gd7TFZY106KVlPVa5jcYD1gaQf98=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAmPf4YLrFg6oQUotqHQeUNWwkvo7jZp1GLU=
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.1 h1:aCvUg6QPl3ibpQUxyLkrEkCHtPqYJL4x9AuhqVqFis4=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
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/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
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/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774 h1:a4tQYYYuK9QdeO/+kEvNYyuR21S+7ve5EANok6hABhI=
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
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/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.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
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/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-20180906233101-161cd47e91fd/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-20190206173232-65e2d4e15006 h1:bfLnR+k0tq5Lqt6dflRLcZiz6UaXCMt3vhYJ1l4FQ80=
golang.org/x/net v0.0.0-20190206173232-65e2d4e15006/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
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/oauth2 v0.0.0-20190402181905-9f3314589c9a h1:tImsplftrFpALCYumobsd0K86vlAs/eXGFms2txfJfA=
golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
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=
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.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
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.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs=
golang.org/x/oauth2 v0.21.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-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
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-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
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/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313 h1:pczuHS43Cp2ktBEEmLwScxgjWsBSzdaQiKzUyf3DTTc=
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=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.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.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db h1:6/JqlYfC1CCaLnGceQTI+sDGhC9UBSPAsBqI0Gun6kU=
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20161028155119-f51c12702a4d h1:TnM+PKb3ylGmZvyPXmo9m/wktg7Jn/a/fNmr33HSj8g=
golang.org/x/time v0.0.0-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
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.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
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/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
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=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
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=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.0 h1:3zYtXIO92bvsdS3ggAdA8Gb4Azj0YU+TVY1uGYNFA8o=
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
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/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.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.6 h1:97YCGUei5WVbkKfogoJQsLwUJ17cWvpLrgNvlcbxikE=
gopkg.in/yaml.v2 v2.2.6/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
k8s.io/api v0.0.0-20190620084959-7cf5895f2711 h1:BblVYz/wE5WtBsD/Gvu54KyBUTJMflolzc5I2DTvh50=
k8s.io/api v0.0.0-20190620084959-7cf5895f2711/go.mod h1:TBhBqb1AWbBQbW3XRusr7n7E4v2+5ZY8r8sAMnyFC5A=
k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719 h1:uV4S5IB5g4Nvi+TBVNf3e9L4wrirlwYJ6w88jUQxTUw=
k8s.io/apimachinery v0.0.0-20190612205821-1799e75a0719/go.mod h1:I4A+glKBHiTgiEjQiCCQfCAIcIMFGt291SmsvcrFzJA=
k8s.io/client-go v0.0.0-20190620085101-78d2af792bab h1:E8Fecph0qbNsAbijJJQryKu4Oi9QTp5cVpjTE+nqg6g=
k8s.io/client-go v0.0.0-20190620085101-78d2af792bab/go.mod h1:E95RaSlHr79aHaX0aGSwcPNfygDiPKOVXdmivCIZT0k=
k8s.io/klog v0.3.1 h1:RVgyDHY/kFKtLqh67NvEWIgkMneNoIrdkN0CxDSQc68=
k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v0.4.0 h1:lCJCxf/LIowc2IGS9TPjWDyXY4nOmdGdfcwwDQCOURQ=
k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
k8s.io/utils v0.0.0-20190221042446-c2654d5206da h1:ElyM7RPonbKnQqOcw7dG2IK5uvQQn3b/WPHqD5mBvP4=
k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
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.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ=
k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04=
k8s.io/apimachinery v0.30.3 h1:q1laaWCmrszyQuSQCfNB8cFgCuDAoPszKY4ucAjDwHc=
k8s.io/apimachinery v0.30.3/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
k8s.io/client-go v0.30.3 h1:bHrJu3xQZNXIi8/MoxYtZBBWQQXwy16zqJwloXXfD3k=
k8s.io/client-go v0.30.3/go.mod h1:8d4pf8vYu665/kUbsxWAQ/JDBNWqfFeZnvFiVdmx89U=
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-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=

View File

@@ -0,0 +1,432 @@
package integration_test
import (
"bytes"
"context"
"encoding/json"
"io"
"os"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"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/pkg/di"
"github.com/int128/kubelogin/pkg/infrastructure/browser"
"github.com/int128/kubelogin/pkg/testing/clock"
"github.com/int128/kubelogin/pkg/testing/logger"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
)
// Run the integration tests of the credential plugin use-case.
//
// 1. Start the auth server.
// 2. Run the Cmd.
// 3. Open a request for the local server.
// 4. Verify the output.
func TestCredentialPlugin(t *testing.T) {
timeout := 10 * time.Second
now := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
tokenCacheDir := t.TempDir()
for name, tc := range map[string]struct {
keyPair keypair.KeyPair
args []string
}{
"NoTLS": {},
"TLS": {
keyPair: keypair.Server,
args: []string{"--certificate-authority", keypair.Server.CACertPath},
},
} {
httpDriverOption := httpdriver.Option{
TLSConfig: tc.keyPair.TLSConfig,
BodyContains: "Authenticated",
}
t.Run(name, func(t *testing.T) {
t.Run("AuthCode", func(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{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
},
Response: oidcserver.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
var stdout bytes.Buffer
runGetToken(t, ctx, getTokenConfig{
tokenCacheDir: tokenCacheDir,
issuerURL: sv.IssuerURL(),
httpDriver: httpdriver.New(ctx, t, httpDriverOption),
now: now,
stdout: &stdout,
args: tc.args,
})
assertCredentialPluginStdout(t, &stdout, sv.LastTokenResponse().IDToken, now.Add(time.Hour))
})
t.Run("ROPC", func(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{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
Username: "USER1",
Password: "PASS1",
},
Response: oidcserver.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
var stdout bytes.Buffer
runGetToken(t, ctx, getTokenConfig{
tokenCacheDir: tokenCacheDir,
issuerURL: sv.IssuerURL(),
httpDriver: httpdriver.Zero(t),
now: now,
stdout: &stdout,
args: append([]string{
"--username", "USER1",
"--password", "PASS1",
}, tc.args...),
})
assertCredentialPluginStdout(t, &stdout, sv.LastTokenResponse().IDToken, now.Add(time.Hour))
})
t.Run("TokenCacheLifecycle", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
sv := oidcserver.New(t, tc.keyPair, oidcserver.Config{})
t.Run("NoCache", func(t *testing.T) {
sv.SetConfig(oidcserver.Config{
Want: oidcserver.Want{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
},
Response: oidcserver.Response{
IDTokenExpiry: now.Add(time.Hour),
RefreshToken: "REFRESH_TOKEN_1",
},
})
var stdout bytes.Buffer
runGetToken(t, ctx, getTokenConfig{
tokenCacheDir: tokenCacheDir,
issuerURL: sv.IssuerURL(),
httpDriver: httpdriver.New(ctx, t, httpDriverOption),
now: now,
stdout: &stdout,
args: tc.args,
})
assertCredentialPluginStdout(t, &stdout, sv.LastTokenResponse().IDToken, now.Add(time.Hour))
})
t.Run("Valid", func(t *testing.T) {
sv.SetConfig(oidcserver.Config{})
var stdout bytes.Buffer
runGetToken(t, ctx, getTokenConfig{
tokenCacheDir: tokenCacheDir,
issuerURL: sv.IssuerURL(),
httpDriver: httpdriver.Zero(t),
now: now,
stdout: &stdout,
args: tc.args,
})
assertCredentialPluginStdout(t, &stdout, sv.LastTokenResponse().IDToken, now.Add(time.Hour))
})
t.Run("Refresh", func(t *testing.T) {
sv.SetConfig(oidcserver.Config{
Want: oidcserver.Want{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
RefreshToken: "REFRESH_TOKEN_1",
},
Response: oidcserver.Response{
IDTokenExpiry: now.Add(3 * time.Hour),
RefreshToken: "REFRESH_TOKEN_2",
},
})
var stdout bytes.Buffer
runGetToken(t, ctx, getTokenConfig{
tokenCacheDir: tokenCacheDir,
issuerURL: sv.IssuerURL(),
httpDriver: httpdriver.New(ctx, t, httpDriverOption),
now: now.Add(2 * time.Hour),
stdout: &stdout,
args: tc.args,
})
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{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
RefreshToken: "REFRESH_TOKEN_2",
},
Response: oidcserver.Response{
IDTokenExpiry: now.Add(5 * time.Hour),
},
})
var stdout bytes.Buffer
runGetToken(t, ctx, getTokenConfig{
tokenCacheDir: tokenCacheDir,
issuerURL: sv.IssuerURL(),
httpDriver: httpdriver.New(ctx, t, httpDriverOption),
now: now.Add(4 * time.Hour),
stdout: &stdout,
args: tc.args,
})
assertCredentialPluginStdout(t, &stdout, sv.LastTokenResponse().IDToken, now.Add(5*time.Hour))
})
})
})
}
t.Run("PKCE", func(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{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
CodeChallengeMethod: "S256",
},
Response: oidcserver.Response{
IDTokenExpiry: now.Add(time.Hour),
CodeChallengeMethodsSupported: []string{"plain", "S256"},
},
})
var stdout bytes.Buffer
runGetToken(t, ctx, getTokenConfig{
tokenCacheDir: tokenCacheDir,
issuerURL: sv.IssuerURL(),
httpDriver: httpdriver.New(ctx, t, httpdriver.Option{BodyContains: "Authenticated"}),
now: now,
stdout: &stdout,
})
assertCredentialPluginStdout(t, &stdout, sv.LastTokenResponse().IDToken, now.Add(time.Hour))
})
t.Run("TLSData", func(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{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
},
Response: oidcserver.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
var stdout bytes.Buffer
runGetToken(t, ctx, getTokenConfig{
tokenCacheDir: tokenCacheDir,
issuerURL: sv.IssuerURL(),
httpDriver: httpdriver.New(ctx, t, httpdriver.Option{TLSConfig: keypair.Server.TLSConfig, BodyContains: "Authenticated"}),
now: now,
stdout: &stdout,
args: []string{"--certificate-authority-data", keypair.Server.CACertBase64},
})
assertCredentialPluginStdout(t, &stdout, sv.LastTokenResponse().IDToken, now.Add(time.Hour))
})
t.Run("ExtraScopes", func(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{
Scope: "email profile openid",
RedirectURIPrefix: "http://localhost:",
},
Response: oidcserver.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
var stdout bytes.Buffer
runGetToken(t, ctx, getTokenConfig{
tokenCacheDir: tokenCacheDir,
issuerURL: sv.IssuerURL(),
httpDriver: httpdriver.New(ctx, t, httpdriver.Option{BodyContains: "Authenticated"}),
now: now,
stdout: &stdout,
args: []string{
"--oidc-extra-scope", "email",
"--oidc-extra-scope", "profile",
},
})
assertCredentialPluginStdout(t, &stdout, sv.LastTokenResponse().IDToken, now.Add(time.Hour))
})
t.Run("OpenURLAfterAuthentication", func(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{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
},
Response: oidcserver.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
var stdout bytes.Buffer
runGetToken(t, ctx, getTokenConfig{
tokenCacheDir: tokenCacheDir,
issuerURL: sv.IssuerURL(),
httpDriver: httpdriver.New(ctx, t, httpdriver.Option{BodyContains: "URL=https://example.com/success"}),
now: now,
stdout: &stdout,
args: []string{"--open-url-after-authentication", "https://example.com/success"},
})
assertCredentialPluginStdout(t, &stdout, sv.LastTokenResponse().IDToken, now.Add(time.Hour))
})
t.Run("RedirectURLHostname", func(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{
Scope: "openid",
RedirectURIPrefix: "http://127.0.0.1:",
},
Response: oidcserver.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
var stdout bytes.Buffer
runGetToken(t, ctx, getTokenConfig{
tokenCacheDir: tokenCacheDir,
issuerURL: sv.IssuerURL(),
httpDriver: httpdriver.New(ctx, t, httpdriver.Option{BodyContains: "Authenticated"}),
now: now,
stdout: &stdout,
args: []string{"--oidc-redirect-url-hostname", "127.0.0.1"},
})
assertCredentialPluginStdout(t, &stdout, sv.LastTokenResponse().IDToken, now.Add(time.Hour))
})
t.Run("RedirectURLHTTPS", func(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{
Scope: "openid",
RedirectURIPrefix: "https://localhost:",
},
Response: oidcserver.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
var stdout bytes.Buffer
runGetToken(t, ctx, getTokenConfig{
tokenCacheDir: tokenCacheDir,
issuerURL: sv.IssuerURL(),
httpDriver: httpdriver.New(ctx, t, httpdriver.Option{
TLSConfig: keypair.Server.TLSConfig,
BodyContains: "Authenticated",
}),
now: now,
stdout: &stdout,
args: []string{
"--local-server-cert", keypair.Server.CertPath,
"--local-server-key", keypair.Server.KeyPath,
},
})
assertCredentialPluginStdout(t, &stdout, sv.LastTokenResponse().IDToken, now.Add(time.Hour))
})
t.Run("ExtraParams", func(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{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
ExtraParams: map[string]string{
"ttl": "86400",
"reauth": "false",
},
},
Response: oidcserver.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
var stdout bytes.Buffer
runGetToken(t, ctx, getTokenConfig{
tokenCacheDir: tokenCacheDir,
issuerURL: sv.IssuerURL(),
httpDriver: httpdriver.New(ctx, t, httpdriver.Option{BodyContains: "Authenticated"}),
now: now,
stdout: &stdout,
args: []string{
"--oidc-auth-request-extra-params", "ttl=86400",
"--oidc-auth-request-extra-params", "reauth=false",
},
})
assertCredentialPluginStdout(t, &stdout, sv.LastTokenResponse().IDToken, now.Add(time.Hour))
})
}
type getTokenConfig struct {
tokenCacheDir string
issuerURL string
httpDriver browser.Interface
stdout io.Writer
now time.Time
args []string
}
func runGetToken(t *testing.T, ctx context.Context, cfg getTokenConfig) {
cmd := di.NewCmdForHeadless(clock.Fake(cfg.now), os.Stdin, cfg.stdout, logger.New(t), cfg.httpDriver)
exitCode := cmd.Run(ctx, append([]string{
"kubelogin",
"get-token",
"--token-cache-dir", cfg.tokenCacheDir,
"--oidc-issuer-url", cfg.issuerURL,
"--oidc-client-id", "kubernetes",
"--listen-address", "127.0.0.1:0",
}, cfg.args...), "latest")
if exitCode != 0 {
t.Errorf("exit status wants 0 but %d", exitCode)
}
}
func assertCredentialPluginStdout(t *testing.T, stdout io.Reader, token string, expiry time.Time) {
var got clientauthenticationv1beta1.ExecCredential
if err := json.NewDecoder(stdout).Decode(&got); err != nil {
t.Errorf("could not decode json of the credential plugin: %s", err)
return
}
want := clientauthenticationv1beta1.ExecCredential{
TypeMeta: metav1.TypeMeta{
APIVersion: "client.authentication.k8s.io/v1beta1",
Kind: "ExecCredential",
},
Status: &clientauthenticationv1beta1.ExecCredentialStatus{
Token: token,
ExpirationTimestamp: &metav1.Time{Time: expiry},
},
}
if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("kubeconfig mismatch (-want +got):\n%s", diff)
}
}

View File

@@ -0,0 +1,78 @@
// Package httpdriver provides a test double of the browser.
package httpdriver
import (
"context"
"crypto/tls"
"io"
"net/http"
"strings"
"testing"
)
type Option struct {
TLSConfig *tls.Config
BodyContains string
}
// New returns a client to simulate browser access.
func New(ctx context.Context, t *testing.T, o Option) *client {
return &client{ctx, t, o}
}
// Zero returns a client which call is not expected.
func Zero(t *testing.T) *zeroClient {
return &zeroClient{t}
}
type client struct {
ctx context.Context
t *testing.T
o Option
}
func (c *client) Open(url string) error {
client := http.Client{Transport: &http.Transport{TLSClientConfig: c.o.TLSConfig}}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
c.t.Errorf("could not create a request: %s", err)
return nil
}
req = req.WithContext(c.ctx)
resp, err := client.Do(req)
if err != nil {
c.t.Errorf("could not send a request: %s", err)
return nil
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
c.t.Errorf("StatusCode wants 200 but %d", resp.StatusCode)
}
b, err := io.ReadAll(resp.Body)
if err != nil {
c.t.Errorf("could not read body: %s", err)
return nil
}
body := string(b)
if !strings.Contains(body, c.o.BodyContains) {
c.t.Errorf("body should contain %s but was %s", c.o.BodyContains, body)
}
return nil
}
func (c *client) OpenCommand(_ context.Context, url, _ string) error {
return c.Open(url)
}
type zeroClient struct {
t *testing.T
}
func (c *zeroClient) Open(url string) error {
c.t.Errorf("unexpected function call Open(%s)", url)
return nil
}
func (c *zeroClient) OpenCommand(_ context.Context, url, _ string) error {
return c.Open(url)
}

View File

@@ -0,0 +1,61 @@
package keypair
import (
"crypto/tls"
"crypto/x509"
"encoding/base64"
"io"
"os"
"strings"
)
// KeyPair represents a pair of certificate and key.
type KeyPair struct {
CertPath string
KeyPath string
CACertPath string
CACertBase64 string
TLSConfig *tls.Config
}
// None represents non-TLS.
var None KeyPair
// Server is a KeyPair for TLS server.
// These files should be generated by Makefile before test.
var Server = KeyPair{
CertPath: "keypair/testdata/server.crt",
KeyPath: "keypair/testdata/server.key",
CACertPath: "keypair/testdata/ca.crt",
CACertBase64: readAsBase64("keypair/testdata/ca.crt"),
TLSConfig: newTLSConfig("keypair/testdata/ca.crt"),
}
func readAsBase64(name string) string {
f, err := os.Open(name)
if err != nil {
panic(err)
}
defer f.Close()
var s strings.Builder
e := base64.NewEncoder(base64.StdEncoding, &s)
if _, err := io.Copy(e, f); err != nil {
panic(err)
}
if err := e.Close(); err != nil {
panic(err)
}
return s.String()
}
func newTLSConfig(name string) *tls.Config {
b, err := os.ReadFile(name)
if err != nil {
panic(err)
}
p := x509.NewCertPool()
if !p.AppendCertsFromPEM(b) {
panic("could not append the CA cert")
}
return &tls.Config{RootCAs: p}
}

View File

@@ -0,0 +1,26 @@
EXPIRY := 3650
OUTPUT_DIR := testdata
TARGETS := ca.key
TARGETS += ca.crt
TARGETS += server.key
TARGETS += server.crt
.PHONY: all
all: $(TARGETS)
ca.key:
openssl genrsa -out $@ 2048
ca.csr: ca.key
openssl req -new -key ca.key -out $@ -subj "/CN=hello-ca" -config openssl.cnf
ca.crt: ca.key ca.csr
openssl x509 -req -in ca.csr -signkey ca.key -out $@ -days $(EXPIRY)
server.key:
openssl genrsa -out $@ 2048
server.csr: openssl.cnf server.key
openssl req -new -key server.key -out $@ -subj "/CN=localhost" -config openssl.cnf
server.crt: openssl.cnf server.csr ca.crt ca.key
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out $@ -sha256 -days $(EXPIRY) -extensions v3_req -extfile openssl.cnf
.PHONY: clean
clean:
-rm -v $(TARGETS)

View File

@@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE-----
MIICojCCAYoCCQCNsdXicWqF2DANBgkqhkiG9w0BAQUFADATMREwDwYDVQQDDAho
ZWxsby1jYTAeFw0yMDAyMDYwMTMzMzNaFw0zMDAyMDMwMTMzMzNaMBMxETAPBgNV
BAMMCGhlbGxvLWNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxcPN
dS88B6ewqVn/m9yO74OLIwNrqMci8l7olP9XlcJhxUZs+3WZQpsSj5nC4yEx8uPQ
bTtBKnXXVDe+8k7OsLTruu9+isTaYk4o/TZbuw/N31ZAiT0pJw8hdypTQyMLbeDr
Vl4bbrfbYywx30DyrHxUkgzOWs459Uwc1wWu0W7M21GY4KENHFE3OAcD58FMvvrh
vgkslATwwW4M2UtXUFJ8XHh26g/J450DU2gwNxpcSdIsvFE6zSyAxU55RElph7mE
ru9cNWAYhCRZvlZQ2VlH7C6JQ3SHyA9RZmBbPpXhtl9zavFkGx2MEwDp/3FmUukR
yJnS2KnAo0QdBeS1LQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQAXGfoDwuKY4TyF
fhKg553Y5I6VDCDc97jyW9yyfc0kvPjQc4EGQV+1eQqMSeh2THpgEEKk9hH/g35a
grPRcBTsEWpbQd16yWyulQeyOtPeWZB2FvAigMaAdMmeXlTs6++gJ6PjPuACa2Jl
nJ/AjCqKFxkn0yEVkPTY0c/I9A12xhCmATqIrQiK1pPowiFxQb4M8Cm0z0AkaJZr
iW0NCOJlLzBqRpFquL4umNaIsxTmOshfM70NpQGRjKREBuK6S0qWsRR0wz4b9Rvi
62qW4zU94q2EDIoCItjHP4twGENXJDC0vLCsKfA5AvbPzszd5/4ifYe2C00Rn7/O
lIxrspMm
-----END CERTIFICATE-----

View File

@@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICrDCCAZQCAQAwEzERMA8GA1UEAwwIaGVsbG8tY2EwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQDFw811LzwHp7CpWf+b3I7vg4sjA2uoxyLyXuiU/1eV
wmHFRmz7dZlCmxKPmcLjITHy49BtO0EqdddUN77yTs6wtOu6736KxNpiTij9Nlu7
D83fVkCJPSknDyF3KlNDIwtt4OtWXhtut9tjLDHfQPKsfFSSDM5azjn1TBzXBa7R
bszbUZjgoQ0cUTc4BwPnwUy++uG+CSyUBPDBbgzZS1dQUnxceHbqD8njnQNTaDA3
GlxJ0iy8UTrNLIDFTnlESWmHuYSu71w1YBiEJFm+VlDZWUfsLolDdIfID1FmYFs+
leG2X3Nq8WQbHYwTAOn/cWZS6RHImdLYqcCjRB0F5LUtAgMBAAGgVDBSBgkqhkiG
9w0BCQ4xRTBDMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgXgMBQGA1UdEQQNMAuCCWxv
Y2FsaG9zdDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQsFAAOCAQEA
o/Uthp3NWx0ydTn/GBZI+vA3gI7Qd9UwLvwkeinldRlPM9DOXpG6LR0C40f6u+fj
mXvUDerveYJI8rpo+Ds0UVqy63AH/zZLG7M96L5Nv2KnK40bkfVNez858Yqp1u17
/ci1ZsQIElU5v2qKozaHdQThDVtD5ZZdZoQwLvBLE/Dwpe/4VZZFh8smPMR+Mhcq
+b7gpSy1RiUffk0ZMjuF9Nc9OODdQMTCf+86i0qWXGVzkhfHKAGv+xarHEztcmxF
GUgUYW8DMvYBjEzaGRM1n0aIFkQO6y8SUXvGMIGBSMC4jfBH3ghIXg1+nD6Uah4D
16r+CLjFsDUdn/DK/fIQVw==
-----END CERTIFICATE REQUEST-----

View File

@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAxcPNdS88B6ewqVn/m9yO74OLIwNrqMci8l7olP9XlcJhxUZs
+3WZQpsSj5nC4yEx8uPQbTtBKnXXVDe+8k7OsLTruu9+isTaYk4o/TZbuw/N31ZA
iT0pJw8hdypTQyMLbeDrVl4bbrfbYywx30DyrHxUkgzOWs459Uwc1wWu0W7M21GY
4KENHFE3OAcD58FMvvrhvgkslATwwW4M2UtXUFJ8XHh26g/J450DU2gwNxpcSdIs
vFE6zSyAxU55RElph7mEru9cNWAYhCRZvlZQ2VlH7C6JQ3SHyA9RZmBbPpXhtl9z
avFkGx2MEwDp/3FmUukRyJnS2KnAo0QdBeS1LQIDAQABAoIBAHSoWtMsaMnPNlu/
thM32K0auIGP6/rkdQ3pxGLX+M9jmY7oSzNOHHj4xssklZyroS45CmLU2Ez2tG1+
cMm4iR4dqwxbaBbtpjDlEDLF1PiUiwmadHlANb1PpJsJwZHR41UOn2QUITR/ig+H
K2gZhM0QjkaU/Uj9a5zyJ/UC6iupmgCtj8ij65B49qKMODxV4gqZstRSZiJ3gb6R
TBeR3PUWQS62MZueEQz2eF0eXkXKsFWcbLfHArjfIJ533zW68A0vabgqOhCwJTks
+rkyaKUjEwJJQcgpCfUI4t9HAwICqYtw0fQdDDaMak2XTDFnGHn1/VfSi818U5Sa
jZ+/uIECgYEA4uCd5ISsLWebSv2r5f97N8+WcW0MSJ0XP5MniiMvlaNOtJmoN3H0
PlgR3uwpH9TNWHITZEEb/I93r2E3f24v2018g0uJuwiRDusxHs7yuxw/93Y5rwtG
3twL1k0GyeLCxfM2y2QQU/awXISx7nNk2f0umvTWmjrEw632oQSWCSECgYEA3yaF
zDk7k1u1GdZAh+pQAyUtjzHSvQjiE2JzLaH8BTorACrczRascX5yyMi0QfLYnoYt
UL9dCb4Z8HUclj55kBSx8anvVtf3XAT3hZ3sm8LV3JLGDeURGS8rGdV+tyFk7zw9
XgvaLj3xjB5CoJvtOhbXvqF9M9yp4TMBb5El7o0CgYBTx5Bm15thNPZCrgQxbbOJ
u42ZmyRDGEeCgYvDVhT3VBP3WxqkRt9juk/3GwxgpcuikpWYmvaDwFL5H5RH6V+g
wy9sqJNWzuYKNU2xS8iU0ezJLA5HFon4OBfi7hTIroUwZgzg9LWW2+zqbVHrdQ9T
9Eumiy1ITNVmUTJW6YOiIQKBgBE4BsEAdZFkVTAeMTKLqQrlFoPjI1DE27UFNsAB
rNG2cFT9+bW1ly7WxAKsQgSIuaBZ2CtP6Nz0l0nPr5oEThsJDcYJB9faqFKoa3Ua
/4PxX9E6Xh/6WfxogFno+HMnF4PCUTXtkjNZQkc+moOMJJ0D4DfsfB3BXDZtWiIC
wDuNAoGBAN5ZFTXwE1VpWxIWq5dV9+0aVOP/eB+h7Pt+u2xyRip31FGcpGEzGniu
VmOzWApW7NmvD0QWtstJWlCpsw+rOptAL0oVunlB70KuYuA+2Q5g/Cw3kUrvXqbe
mkCoV21eFAmpU+I6z/n7pUDXPuUsmTkzmwedv0HUuNSQJmHZOMPD
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1 @@
9E12C7A1AF348811

View File

@@ -0,0 +1,14 @@
[ req ]
distinguished_name = req_distinguished_name
req_extensions = v3_req
[ req_distinguished_name ]
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names
extendedKeyUsage = serverAuth
[alt_names]
DNS.1 = localhost

View File

@@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC7zCCAdegAwIBAgIJAJ4Sx6GvNIgRMA0GCSqGSIb3DQEBCwUAMBMxETAPBgNV
BAMMCGhlbGxvLWNhMB4XDTIwMDIwNjAxMzMzM1oXDTMwMDIwMzAxMzMzM1owFDES
MBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
AQEA3CJvDbbiiY/o9lgzeABLCtZe56h2w9Dzejy02M6F7yVyphLtJr+/AxI8k5Er
MFRitkzgIUkLn/90CZjPI3k5OnLtUAJ4XLj4gUGjziy4TKyVaU0XK41ZSbDAchbW
349lsEgW5ZnL4qNaZeCvvbYec+RroVc6ZXCcDp4BATTkC3gSVF92+TzrrlbkZ5+W
YVeoMpAPWDPq2zwQx4RcYlpkpI/fzLezRqjRcZJx3FDgkGuwwhzXfVUpxJ/DYLXZ
yHCKyaT7e8YIs8e7TRekOwrLCfssfhJSdWopf6aYRZFV+2ovP0Nggn6XJNh/g1QK
o4wzJAf6v5WMc0jEvb7EuSG+nwIDAQABo0UwQzAJBgNVHRMEAjAAMAsGA1UdDwQE
AwIF4DAUBgNVHREEDTALgglsb2NhbGhvc3QwEwYDVR0lBAwwCgYIKwYBBQUHAwEw
DQYJKoZIhvcNAQELBQADggEBACqlq8b7trNRtKUm1PbY7dnrAFCOnV4OT2R98s17
Q6tmCXM1DvQ101W0ih/lh6iPyU4JM2A0kvO+gizuL/Dmvb6oh+3ox0mMLposptso
gCE1K3SXlvlcLdM6hXRJ5+XwlSCHM6o2Y4yABnKjT6Zr+CMh86a5abDx33hkJ4QR
6I+/iBHVLiCVv0wUF3jD/T+HxinEQrB4cQsSgKmfPClrc8n7rkWWE+MdwEL4VZCH
ufabw178aYibVvJ8k3rushjLlftkDyCNno2rz8YWrnaxabVR0EqSPInyYQenmv2r
/CedVKpmdH2RV8ubkwqa0s6cmpRkyu6FS2g3LviJhmm0nwQ=
-----END CERTIFICATE-----

View File

@@ -0,0 +1,17 @@
-----BEGIN CERTIFICATE REQUEST-----
MIICrTCCAZUCAQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0B
AQEFAAOCAQ8AMIIBCgKCAQEA3CJvDbbiiY/o9lgzeABLCtZe56h2w9Dzejy02M6F
7yVyphLtJr+/AxI8k5ErMFRitkzgIUkLn/90CZjPI3k5OnLtUAJ4XLj4gUGjziy4
TKyVaU0XK41ZSbDAchbW349lsEgW5ZnL4qNaZeCvvbYec+RroVc6ZXCcDp4BATTk
C3gSVF92+TzrrlbkZ5+WYVeoMpAPWDPq2zwQx4RcYlpkpI/fzLezRqjRcZJx3FDg
kGuwwhzXfVUpxJ/DYLXZyHCKyaT7e8YIs8e7TRekOwrLCfssfhJSdWopf6aYRZFV
+2ovP0Nggn6XJNh/g1QKo4wzJAf6v5WMc0jEvb7EuSG+nwIDAQABoFQwUgYJKoZI
hvcNAQkOMUUwQzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAUBgNVHREEDTALggls
b2NhbGhvc3QwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQELBQADggEB
ACUQ0j3XuUZY3fso5tEgOGVjVsTU+C4pIsEw3e1KyIB93i56ANKaq1uBLtnlWtYi
R4RxZ3Sf08GzoEHAHpWoQ4BQ3WGDQjxSdezbudWMuNnNyvyhkh36tmmp/PLA4iZD
Q/d1odzGWg1HMqY0/Q3hfz40MQ9IEBBm+5zKw3tLsKNIKdSdlY7Ul3Z9PUsqsOVW
uF0LKsTMEh1CpbYnOBS2EQjComVM5kYfdQwDNh+BMok8rH7mHFYRmrwYUrU9njsM
eoKqhLkoSu6hw1Cgd9Yru5lC541KfxsSN4Cj6rkm+Qv/5zjvIPxYZ+akSQQR9hR3
2O9THHKqaQS0xmD+y8NjfYk=
-----END CERTIFICATE REQUEST-----

View File

@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA3CJvDbbiiY/o9lgzeABLCtZe56h2w9Dzejy02M6F7yVyphLt
Jr+/AxI8k5ErMFRitkzgIUkLn/90CZjPI3k5OnLtUAJ4XLj4gUGjziy4TKyVaU0X
K41ZSbDAchbW349lsEgW5ZnL4qNaZeCvvbYec+RroVc6ZXCcDp4BATTkC3gSVF92
+TzrrlbkZ5+WYVeoMpAPWDPq2zwQx4RcYlpkpI/fzLezRqjRcZJx3FDgkGuwwhzX
fVUpxJ/DYLXZyHCKyaT7e8YIs8e7TRekOwrLCfssfhJSdWopf6aYRZFV+2ovP0Ng
gn6XJNh/g1QKo4wzJAf6v5WMc0jEvb7EuSG+nwIDAQABAoIBAEYvWFb4C0wurOj2
ABrvhP2Ekaesh4kxMp+zgTlqxzsTJnWarS/gjKcPBm9KJon3La3P3tnd7y3pBXcV
2F0IBl4DTHRpBTUS6HBVnENc8LnJgK2dHZkOLPyYtRLrA0Et+A73PQ2hNmchC+5V
b9K9oQH0Pvim1gCHocnrSIi480hQPazO9/gnHvFtu9Tdsx9kM9jgChhh5VaR+nzM
uw6MpUSzCri3/W6K5Hz8F1lLQcZ6o3vyyFtLPjFrWT4J1UiHqAoxuCGeWTvMbGQl
9Cg0SMX4FLBpbIoMonhM3hb9Cw3FVRGU/1i4oF+gEIGlX/v9CPT5HAZmD59rawc8
11x7yTECgYEA8EYVGKauLHeI1nJdCoVrWI73W1wtwt6prJbzltpoAR4tb3Qu6gBX
JQNd+Ifhl28lK6lPnCGk/SsmfiKSp/XE4IyS1GBd2LpxWj5R50GePCg4hAzk9Xyx
M9SJAFQw73pODgu4RWFXTCOMo9crahJ6X/O+MckHqbFqqohJ8nChGDkCgYEA6oro
Ql/ymO7UdYCay7OlzKeg8ud6XgkZ+wkpSG/5TQ0QZWVN3aSOLztEdVfh3PAqWob0
KgVhLmq6CYwq+HSzU92bvFqCgYUMU8tYzeRboGLxyEdAGL+EW0j8wQyZKYR5cNz4
yM0hpM6kbJ0zZqkYVM/XfRT2RTGwTMakF/FOHZcCgYEAmf4guTriuIcoAWEstniK
Myj16ezrO1Df6Eia+B0kuUqxDhSlmL39HDDLQmU8NYU7in8qEcQSbVwBgKgB3HoM
42nVFR5qJ2RfD9qPPar1klKo3iExgRCYtcJKyBYtgt6dNi1WvcjEXX0PP1bBcWtE
WUjrphbUvXKDDabp1eNPrCkCgYBOw/F2APTeyS4Oe+8AQ8eFcDIMARLGK7ZO6Oe1
TO1jI+UCuD+rFI0vbW7zHV1brkf6+OFcj0vwo6TweeMgZ0il/IFFgvva9UyLg3nC
Q1NGDJR4Fv1+kiqn4V4IkuuI1tVVws/F16XZzA/J7g0KB/WE3fvXJMgDuskjL36C
D+aU5wKBgQCvEg+mJYny1QiR/mQuowX34xf4CkMl7Xq9YDH7W/3AlwuPrPNHaZjh
SvSCz9I8vV0E4ur6atazgCblnvA/G3d4r8YYx+e1l30WJHMgoZRxxHMH74tmUPAj
Klic16BJikSQclMeFdlJqf2UHd37eEuYnxorpep8YGP7/eN1ghHWAw==
-----END RSA PRIVATE KEY-----

View File

@@ -2,8 +2,8 @@ package kubeconfig
import (
"html/template"
"io/ioutil"
"os"
"path/filepath"
"testing"
"gopkg.in/yaml.v2"
@@ -22,7 +22,8 @@ type Values struct {
// Create creates a kubeconfig file and returns path to it.
func Create(t *testing.T, v *Values) string {
t.Helper()
f, err := ioutil.TempFile("", "kubeconfig")
name := filepath.Join(t.TempDir(), "kubeconfig")
f, err := os.Create(name)
if err != nil {
t.Fatal(err)
}
@@ -34,7 +35,7 @@ func Create(t *testing.T, v *Values) string {
if err := tpl.Execute(f, v); err != nil {
t.Fatal(err)
}
return f.Name()
return name
}
type AuthProviderConfig struct {

View File

@@ -1,25 +1,24 @@
// Package idp provides a test double of the identity provider of OpenID Connect.
package idp
// Package handler provides a HTTP handler for the OpenID Connect Provider.
package handler
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"testing"
"golang.org/x/xerrors"
)
func NewHandler(t *testing.T, service Service) *Handler {
return &Handler{t, service}
func New(t *testing.T, provider Provider) *Handler {
return &Handler{t, provider}
}
// Handler provides a HTTP handler for the identity provider of OpenID Connect.
// You need to implement the Service interface.
// Handler provides a HTTP handler 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 {
t *testing.T
service Service
t *testing.T
provider Provider
}
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
@@ -29,7 +28,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.t.Logf("%d %s %s", wr.statusCode, r.Method, r.RequestURI)
return
}
if errResp := new(ErrorResponse); xerrors.As(err, &errResp) {
if errResp := new(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)
@@ -58,74 +57,80 @@ func (h *Handler) serveHTTP(w http.ResponseWriter, r *http.Request) error {
p := r.URL.Path
switch {
case m == "GET" && p == "/.well-known/openid-configuration":
discoveryResponse := h.service.Discovery()
discoveryResponse := h.provider.Discovery()
w.Header().Add("Content-Type", "application/json")
e := json.NewEncoder(w)
if err := e.Encode(discoveryResponse); err != nil {
return xerrors.Errorf("could not render json: %w", err)
return fmt.Errorf("could not render json: %w", err)
}
case m == "GET" && p == "/certs":
certificatesResponse := h.service.GetCertificates()
certificatesResponse := h.provider.GetCertificates()
w.Header().Add("Content-Type", "application/json")
e := json.NewEncoder(w)
if err := e.Encode(certificatesResponse); err != nil {
return xerrors.Errorf("could not render json: %w", err)
return fmt.Errorf("could not render json: %w", err)
}
case m == "GET" && p == "/auth":
// 3.1.2.1. Authentication Request
// https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
q := r.URL.Query()
redirectURI, scope, state, nonce := q.Get("redirect_uri"), q.Get("scope"), q.Get("state"), q.Get("nonce")
code, err := h.service.AuthenticateCode(scope, nonce)
redirectURI, state := q.Get("redirect_uri"), q.Get("state")
code, err := h.provider.AuthenticateCode(AuthenticationRequest{
RedirectURI: redirectURI,
State: state,
Scope: q.Get("scope"),
Nonce: q.Get("nonce"),
CodeChallenge: q.Get("code_challenge"),
CodeChallengeMethod: q.Get("code_challenge_method"),
RawQuery: q,
})
if err != nil {
return xerrors.Errorf("authentication error: %w", err)
return fmt.Errorf("authentication error: %w", err)
}
to := fmt.Sprintf("%s?state=%s&code=%s", redirectURI, state, code)
http.Redirect(w, r, to, 302)
case m == "POST" && p == "/token":
if err := r.ParseForm(); err != nil {
return xerrors.Errorf("could not parse the form: %w", err)
return fmt.Errorf("could not parse the form: %w", err)
}
grantType := r.Form.Get("grant_type")
switch grantType {
case "authorization_code":
// 3.1.3.1. Token Request
// https://openid.net/specs/openid-connect-core-1_0.html#TokenRequest
code := r.Form.Get("code")
tokenResponse, err := h.service.Exchange(code)
tokenResponse, err := h.provider.Exchange(TokenRequest{
Code: r.Form.Get("code"),
CodeVerifier: r.Form.Get("code_verifier"),
})
if err != nil {
return xerrors.Errorf("token request error: %w", err)
return fmt.Errorf("token request error: %w", err)
}
w.Header().Add("Content-Type", "application/json")
e := json.NewEncoder(w)
if err := e.Encode(tokenResponse); err != nil {
return xerrors.Errorf("could not render json: %w", err)
return fmt.Errorf("could not render json: %w", err)
}
case "password":
// 4.3. Resource Owner Password Credentials Grant
// https://tools.ietf.org/html/rfc6749#section-4.3
username, password, scope := r.Form.Get("username"), r.Form.Get("password"), r.Form.Get("scope")
tokenResponse, err := h.service.AuthenticatePassword(username, password, scope)
tokenResponse, err := h.provider.AuthenticatePassword(username, password, scope)
if err != nil {
return xerrors.Errorf("authentication error: %w", err)
return fmt.Errorf("authentication error: %w", err)
}
w.Header().Add("Content-Type", "application/json")
e := json.NewEncoder(w)
if err := e.Encode(tokenResponse); err != nil {
return xerrors.Errorf("could not render json: %w", err)
return fmt.Errorf("could not render json: %w", err)
}
case "refresh_token":
// 12.1. Refresh Request
// https://openid.net/specs/openid-connect-core-1_0.html#RefreshingAccessToken
refreshToken := r.Form.Get("refresh_token")
tokenResponse, err := h.service.Refresh(refreshToken)
tokenResponse, err := h.provider.Refresh(refreshToken)
if err != nil {
return xerrors.Errorf("token refresh error: %w", err)
return fmt.Errorf("token refresh error: %w", err)
}
w.Header().Add("Content-Type", "application/json")
e := json.NewEncoder(w)
if err := e.Encode(tokenResponse); err != nil {
return xerrors.Errorf("could not render json: %w", err)
return fmt.Errorf("could not render json: %w", err)
}
default:
// 5.2. Error Response

View File

@@ -1,23 +1,19 @@
package idp
//go:generate mockgen -destination mock_idp/mock_service.go github.com/int128/kubelogin/e2e_test/idp Service
package handler
import (
"crypto/rsa"
"encoding/base64"
"fmt"
"math/big"
"net/url"
)
// Service provides discovery and authentication methods.
// Provider provides discovery and authentication methods.
// 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.
type Service interface {
type Provider interface {
Discovery() *DiscoveryResponse
GetCertificates() *CertificatesResponse
AuthenticateCode(scope, nonce string) (code string, err error)
Exchange(code string) (*TokenResponse, error)
AuthenticateCode(req AuthenticationRequest) (code string, err error)
Exchange(req TokenRequest) (*TokenResponse, error)
AuthenticatePassword(username, password, scope string) (*TokenResponse, error)
Refresh(refreshToken string) (*TokenResponse, error)
}
@@ -38,26 +34,6 @@ type DiscoveryResponse struct {
CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported"`
}
// NewDiscoveryResponse returns a DiscoveryResponse for the local server.
// This is based on https://accounts.google.com/.well-known/openid-configuration.
func NewDiscoveryResponse(issuer string) *DiscoveryResponse {
return &DiscoveryResponse{
Issuer: issuer,
AuthorizationEndpoint: issuer + "/auth",
TokenEndpoint: issuer + "/token",
JwksURI: issuer + "/certs",
UserinfoEndpoint: issuer + "/userinfo",
RevocationEndpoint: issuer + "/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: []string{"plain", "S256"},
ClaimsSupported: []string{"aud", "email", "exp", "iat", "iss", "name", "sub"},
}
}
type CertificatesResponse struct {
Keys []*CertificatesResponseKey `json:"keys"`
}
@@ -71,21 +47,23 @@ type CertificatesResponseKey struct {
E string `json:"e"`
}
// NewCertificatesResponse returns a CertificatesResponse using the key pair.
// This is used for verifying a signature of ID token.
func NewCertificatesResponse(idTokenKeyPair *rsa.PrivateKey) *CertificatesResponse {
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()),
},
},
}
// AuthenticationRequest represents a type of:
// https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
type AuthenticationRequest struct {
RedirectURI string
State string
Scope string // space separated string
Nonce string
CodeChallenge string
CodeChallengeMethod string
RawQuery url.Values
}
// TokenRequest represents a type of:
// https://openid.net/specs/openid-connect-core-1_0.html#TokenRequest
type TokenRequest struct {
Code string
CodeVerifier string
}
type TokenResponse struct {
@@ -96,17 +74,6 @@ type TokenResponse struct {
IDToken string `json:"id_token"`
}
// NewTokenResponse returns a TokenResponse.
func NewTokenResponse(idToken, refreshToken string) *TokenResponse {
return &TokenResponse{
TokenType: "Bearer",
ExpiresIn: 3600,
AccessToken: "YOUR_ACCESS_TOKEN",
IDToken: idToken,
RefreshToken: refreshToken,
}
}
// ErrorResponse represents an error response described in the following section:
// 5.2 Error Response
// https://tools.ietf.org/html/rfc6749#section-5.2

View File

@@ -0,0 +1,74 @@
// 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,216 @@
// 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,306 @@
package integration_test
import (
"context"
"os"
"testing"
"time"
"github.com/int128/kubelogin/integration_test/httpdriver"
"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/pkg/di"
"github.com/int128/kubelogin/pkg/infrastructure/browser"
"github.com/int128/kubelogin/pkg/testing/clock"
"github.com/int128/kubelogin/pkg/testing/logger"
)
// Run the integration tests of the Login use-case.
//
// 1. Start the auth server.
// 2. Run the Cmd.
// 3. Open a request for the local server.
// 4. Verify the kubeconfig.
func TestStandalone(t *testing.T) {
timeout := 3 * time.Second
now := time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)
for name, tc := range map[string]struct {
keyPair keypair.KeyPair
args []string
}{
"NoTLS": {},
"TLS": {
keyPair: keypair.Server,
},
} {
httpDriverOption := httpdriver.Option{
TLSConfig: tc.keyPair.TLSConfig,
BodyContains: "Authenticated",
}
t.Run(name, func(t *testing.T) {
t.Run("AuthCode", func(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{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
},
Response: oidcserver.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
kubeConfigFilename := kubeconfig.Create(t, &kubeconfig.Values{
Issuer: sv.IssuerURL(),
IDPCertificateAuthority: tc.keyPair.CACertPath,
})
runStandalone(t, ctx, standaloneConfig{
issuerURL: sv.IssuerURL(),
kubeConfigFilename: kubeConfigFilename,
httpDriver: httpdriver.New(ctx, t, httpDriverOption),
now: now,
})
kubeconfig.Verify(t, kubeConfigFilename, kubeconfig.AuthProviderConfig{
IDToken: sv.LastTokenResponse().IDToken,
RefreshToken: sv.LastTokenResponse().RefreshToken,
})
})
t.Run("ROPC", func(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{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
Username: "USER1",
Password: "PASS1",
},
Response: oidcserver.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
kubeConfigFilename := kubeconfig.Create(t, &kubeconfig.Values{
Issuer: sv.IssuerURL(),
IDPCertificateAuthority: tc.keyPair.CACertPath,
})
runStandalone(t, ctx, standaloneConfig{
issuerURL: sv.IssuerURL(),
kubeConfigFilename: kubeConfigFilename,
httpDriver: httpdriver.Zero(t),
now: now,
args: []string{
"--username", "USER1",
"--password", "PASS1",
},
})
kubeconfig.Verify(t, kubeConfigFilename, kubeconfig.AuthProviderConfig{
IDToken: sv.LastTokenResponse().IDToken,
RefreshToken: sv.LastTokenResponse().RefreshToken,
})
})
t.Run("TokenLifecycle", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()
sv := oidcserver.New(t, tc.keyPair, oidcserver.Config{})
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{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
},
Response: oidcserver.Response{
IDTokenExpiry: now.Add(time.Hour),
RefreshToken: "REFRESH_TOKEN_1",
},
})
runStandalone(t, ctx, standaloneConfig{
issuerURL: sv.IssuerURL(),
kubeConfigFilename: kubeConfigFilename,
httpDriver: httpdriver.New(ctx, t, httpDriverOption),
now: now,
})
kubeconfig.Verify(t, kubeConfigFilename, kubeconfig.AuthProviderConfig{
IDToken: sv.LastTokenResponse().IDToken,
RefreshToken: "REFRESH_TOKEN_1",
})
})
t.Run("Valid", func(t *testing.T) {
sv.SetConfig(oidcserver.Config{})
runStandalone(t, ctx, standaloneConfig{
issuerURL: sv.IssuerURL(),
kubeConfigFilename: kubeConfigFilename,
httpDriver: httpdriver.Zero(t),
now: now,
})
kubeconfig.Verify(t, kubeConfigFilename, kubeconfig.AuthProviderConfig{
IDToken: sv.LastTokenResponse().IDToken,
RefreshToken: "REFRESH_TOKEN_1",
})
})
t.Run("Refresh", func(t *testing.T) {
sv.SetConfig(oidcserver.Config{
Want: oidcserver.Want{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
RefreshToken: "REFRESH_TOKEN_1",
},
Response: oidcserver.Response{
IDTokenExpiry: now.Add(3 * time.Hour),
RefreshToken: "REFRESH_TOKEN_2",
},
})
runStandalone(t, ctx, standaloneConfig{
issuerURL: sv.IssuerURL(),
kubeConfigFilename: kubeConfigFilename,
httpDriver: httpdriver.New(ctx, t, httpDriverOption),
now: now.Add(2 * time.Hour),
})
kubeconfig.Verify(t, kubeConfigFilename, kubeconfig.AuthProviderConfig{
IDToken: sv.LastTokenResponse().IDToken,
RefreshToken: "REFRESH_TOKEN_2",
})
})
t.Run("RefreshAgain", func(t *testing.T) {
sv.SetConfig(oidcserver.Config{
Want: oidcserver.Want{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
RefreshToken: "REFRESH_TOKEN_2",
},
Response: oidcserver.Response{
IDTokenExpiry: now.Add(5 * time.Hour),
},
})
runStandalone(t, ctx, standaloneConfig{
issuerURL: sv.IssuerURL(),
kubeConfigFilename: kubeConfigFilename,
httpDriver: httpdriver.New(ctx, t, httpDriverOption),
now: now.Add(4 * time.Hour),
})
kubeconfig.Verify(t, kubeConfigFilename, kubeconfig.AuthProviderConfig{
IDToken: sv.LastTokenResponse().IDToken,
RefreshToken: "REFRESH_TOKEN_2",
})
})
})
})
}
t.Run("TLSData", func(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{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
},
Response: oidcserver.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
kubeConfigFilename := kubeconfig.Create(t, &kubeconfig.Values{
Issuer: sv.IssuerURL(),
IDPCertificateAuthorityData: keypair.Server.CACertBase64,
})
runStandalone(t, ctx, standaloneConfig{
issuerURL: sv.IssuerURL(),
kubeConfigFilename: kubeConfigFilename,
httpDriver: httpdriver.New(ctx, t, httpdriver.Option{TLSConfig: keypair.Server.TLSConfig}),
now: now,
})
kubeconfig.Verify(t, kubeConfigFilename, kubeconfig.AuthProviderConfig{
IDToken: sv.LastTokenResponse().IDToken,
RefreshToken: sv.LastTokenResponse().RefreshToken,
})
})
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{
Scope: "openid",
RedirectURIPrefix: "http://localhost:",
},
Response: oidcserver.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
kubeConfigFilename := kubeconfig.Create(t, &kubeconfig.Values{
Issuer: sv.IssuerURL(),
})
t.Setenv("KUBECONFIG", kubeConfigFilename+string(os.PathListSeparator)+"kubeconfig/testdata/dummy.yaml")
runStandalone(t, ctx, standaloneConfig{
issuerURL: sv.IssuerURL(),
httpDriver: httpdriver.New(ctx, t, httpdriver.Option{}),
now: now,
})
kubeconfig.Verify(t, kubeConfigFilename, kubeconfig.AuthProviderConfig{
IDToken: sv.LastTokenResponse().IDToken,
RefreshToken: sv.LastTokenResponse().RefreshToken,
})
})
t.Run("ExtraScopes", func(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{
Scope: "profile groups openid",
RedirectURIPrefix: "http://localhost:",
},
Response: oidcserver.Response{
IDTokenExpiry: now.Add(time.Hour),
},
})
kubeConfigFilename := kubeconfig.Create(t, &kubeconfig.Values{
Issuer: sv.IssuerURL(),
ExtraScopes: "profile,groups",
})
runStandalone(t, ctx, standaloneConfig{
issuerURL: sv.IssuerURL(),
kubeConfigFilename: kubeConfigFilename,
httpDriver: httpdriver.New(ctx, t, httpdriver.Option{}),
now: now,
})
kubeconfig.Verify(t, kubeConfigFilename, kubeconfig.AuthProviderConfig{
IDToken: sv.LastTokenResponse().IDToken,
RefreshToken: sv.LastTokenResponse().RefreshToken,
})
})
}
type standaloneConfig struct {
issuerURL string
kubeConfigFilename string
httpDriver browser.Interface
now time.Time
args []string
}
func runStandalone(t *testing.T, ctx context.Context, cfg standaloneConfig) {
cmd := di.NewCmdForHeadless(clock.Fake(cfg.now), os.Stdin, os.Stdout, logger.New(t), cfg.httpDriver)
exitCode := cmd.Run(ctx, append([]string{
"kubelogin",
"--kubeconfig", cfg.kubeConfigFilename,
"--listen-address", "127.0.0.1:0",
}, cfg.args...), "HEAD")
if exitCode != 0 {
t.Errorf("exit status wants 0 but %d", exitCode)
}
}

View File

@@ -1,15 +0,0 @@
class Kubelogin < Formula
desc "A kubectl plugin for Kubernetes OpenID Connect authentication"
homepage "https://github.com/int128/kubelogin"
url "https://github.com/int128/kubelogin/releases/download/{{ env "VERSION" }}/kubelogin_darwin_amd64.zip"
version "{{ env "VERSION" }}"
sha256 "{{ sha256 .darwin_amd64_archive }}"
def install
bin.install "kubelogin" => "kubelogin"
ln_s bin/"kubelogin", bin/"kubectl-oidc_login"
end
test do
system "#{bin}/kubelogin -h"
system "#{bin}/kubectl-oidc_login -h"
end
end

View File

@@ -1,64 +0,0 @@
apiVersion: krew.googlecontainertools.github.com/v1alpha2
kind: Plugin
metadata:
name: oidc-login
spec:
homepage: https://github.com/int128/kubelogin
shortDescription: Log in to the OpenID Connect provider
description: |
This is a kubectl plugin for Kubernetes OpenID Connect (OIDC) authentication.
## Credential plugin mode
kubectl executes oidc-login before calling the Kubernetes APIs.
oidc-login automatically opens the browser and you can log in to the provider.
After authentication, kubectl gets the token from oidc-login and you can access the cluster.
See https://github.com/int128/kubelogin#credential-plugin-mode for more.
## Standalone mode
Run `kubectl oidc-login`.
It automatically opens the browser and you can log in to the provider.
After authentication, it writes the token to the kubeconfig and you can access the cluster.
See https://github.com/int128/kubelogin#standalone-mode for more.
caveats: |
You need to setup the OIDC provider, Kubernetes API server, role binding and kubeconfig.
See https://github.com/int128/kubelogin for more.
version: {{ env "VERSION" }}
platforms:
- uri: https://github.com/int128/kubelogin/releases/download/{{ env "VERSION" }}/kubelogin_linux_amd64.zip
sha256: "{{ sha256 .linux_amd64_archive }}"
bin: kubelogin
files:
- from: kubelogin
to: .
- from: LICENSE
to: .
selector:
matchLabels:
os: linux
arch: amd64
- uri: https://github.com/int128/kubelogin/releases/download/{{ env "VERSION" }}/kubelogin_darwin_amd64.zip
sha256: "{{ sha256 .darwin_amd64_archive }}"
bin: kubelogin
files:
- from: kubelogin
to: .
- from: LICENSE
to: .
selector:
matchLabels:
os: darwin
arch: amd64
- uri: https://github.com/int128/kubelogin/releases/download/{{ env "VERSION" }}/kubelogin_windows_amd64.zip
sha256: "{{ sha256 .windows_amd64_archive }}"
bin: kubelogin.exe
files:
- from: kubelogin.exe
to: .
- from: LICENSE
to: .
selector:
matchLabels:
os: windows
arch: amd64

View File

@@ -1,76 +0,0 @@
// Package certpool provides loading certificates from files or base64 encoded string.
package certpool
import (
"crypto/tls"
"crypto/x509"
"encoding/base64"
"io/ioutil"
"github.com/google/wire"
"golang.org/x/xerrors"
)
//go:generate mockgen -destination mock_certpool/mock_certpool.go github.com/int128/kubelogin/pkg/adaptors/certpool FactoryInterface,Interface
// Set provides an implementation and interface.
var Set = wire.NewSet(
wire.Struct(new(Factory), "*"),
wire.Bind(new(FactoryInterface), new(*Factory)),
wire.Struct(new(CertPool), "*"),
wire.Bind(new(Interface), new(*CertPool)),
)
type FactoryInterface interface {
New() Interface
}
type Factory struct{}
// New returns an instance which implements the Interface.
func (f *Factory) New() Interface {
return &CertPool{pool: x509.NewCertPool()}
}
type Interface interface {
AddFile(filename string) error
AddBase64Encoded(s string) error
SetRootCAs(cfg *tls.Config)
}
// CertPool represents a pool of certificates.
type CertPool struct {
pool *x509.CertPool
}
// SetRootCAs sets cfg.RootCAs if it has any certificate.
// Otherwise do nothing.
func (p *CertPool) SetRootCAs(cfg *tls.Config) {
if len(p.pool.Subjects()) > 0 {
cfg.RootCAs = p.pool
}
}
// AddFile loads the certificate from the file.
func (p *CertPool) AddFile(filename string) error {
b, err := ioutil.ReadFile(filename)
if err != nil {
return xerrors.Errorf("could not read %s: %w", filename, err)
}
if !p.pool.AppendCertsFromPEM(b) {
return xerrors.Errorf("could not append certificate from %s", filename)
}
return nil
}
// AddBase64Encoded loads the certificate from the base64 encoded string.
func (p *CertPool) AddBase64Encoded(s string) error {
b, err := base64.StdEncoding.DecodeString(s)
if err != nil {
return xerrors.Errorf("could not decode base64: %w", err)
}
if !p.pool.AppendCertsFromPEM(b) {
return xerrors.Errorf("could not append certificate")
}
return nil
}

View File

@@ -1,62 +0,0 @@
package certpool
import (
"crypto/tls"
"io/ioutil"
"testing"
)
func TestCertPool_AddFile(t *testing.T) {
t.Run("Valid", func(t *testing.T) {
var f Factory
p := f.New()
if err := p.AddFile("testdata/ca1.crt"); err != nil {
t.Errorf("AddFile error: %s", err)
}
var cfg tls.Config
p.SetRootCAs(&cfg)
if n := len(cfg.RootCAs.Subjects()); n != 1 {
t.Errorf("n wants 1 but was %d", n)
}
})
t.Run("Invalid", func(t *testing.T) {
var f Factory
p := f.New()
err := p.AddFile("testdata/Makefile")
if err == nil {
t.Errorf("AddFile wants an error but was nil")
}
})
}
func TestCertPool_AddBase64Encoded(t *testing.T) {
var f Factory
p := f.New()
if err := p.AddBase64Encoded(readFile(t, "testdata/ca2.crt.base64")); err != nil {
t.Errorf("AddBase64Encoded error: %s", err)
}
var cfg tls.Config
p.SetRootCAs(&cfg)
if n := len(cfg.RootCAs.Subjects()); n != 1 {
t.Errorf("n wants 1 but was %d", n)
}
}
func TestCertPool_SetRootCAs(t *testing.T) {
var f Factory
p := f.New()
var cfg tls.Config
p.SetRootCAs(&cfg)
if cfg.RootCAs != nil {
t.Errorf("cfg.RootCAs wants nil but was %+v", cfg.RootCAs)
}
}
func readFile(t *testing.T, filename string) string {
t.Helper()
b, err := ioutil.ReadFile(filename)
if err != nil {
t.Fatalf("ReadFile error: %s", err)
}
return string(b)
}

View File

@@ -1,112 +0,0 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/int128/kubelogin/pkg/adaptors/certpool (interfaces: FactoryInterface,Interface)
// Package mock_certpool is a generated GoMock package.
package mock_certpool
import (
tls "crypto/tls"
gomock "github.com/golang/mock/gomock"
certpool "github.com/int128/kubelogin/pkg/adaptors/certpool"
reflect "reflect"
)
// MockFactoryInterface is a mock of FactoryInterface interface
type MockFactoryInterface struct {
ctrl *gomock.Controller
recorder *MockFactoryInterfaceMockRecorder
}
// MockFactoryInterfaceMockRecorder is the mock recorder for MockFactoryInterface
type MockFactoryInterfaceMockRecorder struct {
mock *MockFactoryInterface
}
// NewMockFactoryInterface creates a new mock instance
func NewMockFactoryInterface(ctrl *gomock.Controller) *MockFactoryInterface {
mock := &MockFactoryInterface{ctrl: ctrl}
mock.recorder = &MockFactoryInterfaceMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockFactoryInterface) EXPECT() *MockFactoryInterfaceMockRecorder {
return m.recorder
}
// New mocks base method
func (m *MockFactoryInterface) New() certpool.Interface {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "New")
ret0, _ := ret[0].(certpool.Interface)
return ret0
}
// New indicates an expected call of New
func (mr *MockFactoryInterfaceMockRecorder) New() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "New", reflect.TypeOf((*MockFactoryInterface)(nil).New))
}
// MockInterface is a mock of Interface interface
type MockInterface struct {
ctrl *gomock.Controller
recorder *MockInterfaceMockRecorder
}
// MockInterfaceMockRecorder is the mock recorder for MockInterface
type MockInterfaceMockRecorder struct {
mock *MockInterface
}
// NewMockInterface creates a new mock instance
func NewMockInterface(ctrl *gomock.Controller) *MockInterface {
mock := &MockInterface{ctrl: ctrl}
mock.recorder = &MockInterfaceMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder {
return m.recorder
}
// AddBase64Encoded mocks base method
func (m *MockInterface) AddBase64Encoded(arg0 string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddBase64Encoded", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// AddBase64Encoded indicates an expected call of AddBase64Encoded
func (mr *MockInterfaceMockRecorder) AddBase64Encoded(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddBase64Encoded", reflect.TypeOf((*MockInterface)(nil).AddBase64Encoded), arg0)
}
// AddFile mocks base method
func (m *MockInterface) AddFile(arg0 string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddFile", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// AddFile indicates an expected call of AddFile
func (mr *MockInterfaceMockRecorder) AddFile(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddFile", reflect.TypeOf((*MockInterface)(nil).AddFile), arg0)
}
// SetRootCAs mocks base method
func (m *MockInterface) SetRootCAs(arg0 *tls.Config) {
m.ctrl.T.Helper()
m.ctrl.Call(m, "SetRootCAs", arg0)
}
// SetRootCAs indicates an expected call of SetRootCAs
func (mr *MockInterfaceMockRecorder) SetRootCAs(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetRootCAs", reflect.TypeOf((*MockInterface)(nil).SetRootCAs), arg0)
}

View File

@@ -1,330 +0,0 @@
package cmd
import (
"context"
"testing"
"github.com/golang/mock/gomock"
"github.com/int128/kubelogin/pkg/adaptors/logger/mock_logger"
"github.com/int128/kubelogin/pkg/usecases/authentication"
"github.com/int128/kubelogin/pkg/usecases/credentialplugin"
"github.com/int128/kubelogin/pkg/usecases/credentialplugin/mock_credentialplugin"
"github.com/int128/kubelogin/pkg/usecases/standalone"
"github.com/int128/kubelogin/pkg/usecases/standalone/mock_standalone"
)
func TestCmd_Run(t *testing.T) {
const executable = "kubelogin"
const version = "HEAD"
t.Run("root", func(t *testing.T) {
tests := map[string]struct {
args []string
in standalone.Input
}{
"Defaults": {
args: []string{executable},
in: standalone.Input{
GrantOptionSet: authentication.GrantOptionSet{
AuthCodeOption: &authentication.AuthCodeOption{
BindAddress: []string{"127.0.0.1:8000", "127.0.0.1:18000"},
},
},
},
},
"FullOptions": {
args: []string{executable,
"--kubeconfig", "/path/to/kubeconfig",
"--context", "hello.k8s.local",
"--user", "google",
"--certificate-authority", "/path/to/cacert",
"--insecure-skip-tls-verify",
"-v1",
"--grant-type", "authcode",
"--listen-port", "10080",
"--listen-port", "20080",
"--skip-open-browser",
"--username", "USER",
"--password", "PASS",
},
in: standalone.Input{
KubeconfigFilename: "/path/to/kubeconfig",
KubeconfigContext: "hello.k8s.local",
KubeconfigUser: "google",
CACertFilename: "/path/to/cacert",
SkipTLSVerify: true,
GrantOptionSet: authentication.GrantOptionSet{
AuthCodeOption: &authentication.AuthCodeOption{
BindAddress: []string{"127.0.0.1:10080", "127.0.0.1:20080"},
SkipOpenBrowser: true,
},
},
},
},
"GrantType=authcode-keyboard": {
args: []string{executable,
"--grant-type", "authcode-keyboard",
},
in: standalone.Input{
GrantOptionSet: authentication.GrantOptionSet{
AuthCodeKeyboardOption: &authentication.AuthCodeKeyboardOption{},
},
},
},
"GrantType=password": {
args: []string{executable,
"--grant-type", "password",
"--listen-port", "10080",
"--listen-port", "20080",
"--username", "USER",
"--password", "PASS",
},
in: standalone.Input{
GrantOptionSet: authentication.GrantOptionSet{
ROPCOption: &authentication.ROPCOption{
Username: "USER",
Password: "PASS",
},
},
},
},
"GrantType=auto": {
args: []string{executable,
"--listen-port", "10080",
"--listen-port", "20080",
"--username", "USER",
"--password", "PASS",
},
in: standalone.Input{
GrantOptionSet: authentication.GrantOptionSet{
ROPCOption: &authentication.ROPCOption{
Username: "USER",
Password: "PASS",
},
},
},
},
}
for name, c := range tests {
t.Run(name, func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ctx := context.TODO()
mockStandalone := mock_standalone.NewMockInterface(ctrl)
mockStandalone.EXPECT().
Do(ctx, c.in)
cmd := Cmd{
Root: &Root{
Standalone: mockStandalone,
Logger: mock_logger.New(t),
},
Logger: mock_logger.New(t),
}
exitCode := cmd.Run(ctx, c.args, version)
if exitCode != 0 {
t.Errorf("exitCode wants 0 but %d", exitCode)
}
})
}
t.Run("TooManyArgs", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
cmd := Cmd{
Root: &Root{
Standalone: mock_standalone.NewMockInterface(ctrl),
Logger: mock_logger.New(t),
},
Logger: mock_logger.New(t),
}
exitCode := cmd.Run(context.TODO(), []string{executable, "some"}, version)
if exitCode != 1 {
t.Errorf("exitCode wants 1 but %d", exitCode)
}
})
})
t.Run("get-token", func(t *testing.T) {
tests := map[string]struct {
args []string
in credentialplugin.Input
}{
"Defaults": {
args: []string{executable,
"get-token",
"--oidc-issuer-url", "https://issuer.example.com",
"--oidc-client-id", "YOUR_CLIENT_ID",
},
in: credentialplugin.Input{
TokenCacheDir: defaultTokenCacheDir,
IssuerURL: "https://issuer.example.com",
ClientID: "YOUR_CLIENT_ID",
GrantOptionSet: authentication.GrantOptionSet{
AuthCodeOption: &authentication.AuthCodeOption{
BindAddress: []string{"127.0.0.1:8000", "127.0.0.1:18000"},
},
},
},
},
"FullOptions": {
args: []string{executable,
"get-token",
"--oidc-issuer-url", "https://issuer.example.com",
"--oidc-client-id", "YOUR_CLIENT_ID",
"--oidc-client-secret", "YOUR_CLIENT_SECRET",
"--oidc-extra-scope", "email",
"--oidc-extra-scope", "profile",
"--certificate-authority", "/path/to/cacert",
"--insecure-skip-tls-verify",
"-v1",
"--grant-type", "authcode",
"--listen-port", "10080",
"--listen-port", "20080",
"--skip-open-browser",
"--username", "USER",
"--password", "PASS",
},
in: credentialplugin.Input{
TokenCacheDir: defaultTokenCacheDir,
IssuerURL: "https://issuer.example.com",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
ExtraScopes: []string{"email", "profile"},
CACertFilename: "/path/to/cacert",
SkipTLSVerify: true,
GrantOptionSet: authentication.GrantOptionSet{
AuthCodeOption: &authentication.AuthCodeOption{
BindAddress: []string{"127.0.0.1:10080", "127.0.0.1:20080"},
SkipOpenBrowser: true,
},
},
},
},
"GrantType=authcode-keyboard": {
args: []string{executable,
"get-token",
"--oidc-issuer-url", "https://issuer.example.com",
"--oidc-client-id", "YOUR_CLIENT_ID",
"--grant-type", "authcode-keyboard",
},
in: credentialplugin.Input{
TokenCacheDir: defaultTokenCacheDir,
IssuerURL: "https://issuer.example.com",
ClientID: "YOUR_CLIENT_ID",
GrantOptionSet: authentication.GrantOptionSet{
AuthCodeKeyboardOption: &authentication.AuthCodeKeyboardOption{},
},
},
},
"GrantType=password": {
args: []string{executable,
"get-token",
"--oidc-issuer-url", "https://issuer.example.com",
"--oidc-client-id", "YOUR_CLIENT_ID",
"--grant-type", "password",
"--listen-port", "10080",
"--listen-port", "20080",
"--username", "USER",
"--password", "PASS",
},
in: credentialplugin.Input{
TokenCacheDir: defaultTokenCacheDir,
IssuerURL: "https://issuer.example.com",
ClientID: "YOUR_CLIENT_ID",
GrantOptionSet: authentication.GrantOptionSet{
ROPCOption: &authentication.ROPCOption{
Username: "USER",
Password: "PASS",
},
},
},
},
"GrantType=auto": {
args: []string{executable,
"get-token",
"--oidc-issuer-url", "https://issuer.example.com",
"--oidc-client-id", "YOUR_CLIENT_ID",
"--listen-port", "10080",
"--listen-port", "20080",
"--username", "USER",
"--password", "PASS",
},
in: credentialplugin.Input{
TokenCacheDir: defaultTokenCacheDir,
IssuerURL: "https://issuer.example.com",
ClientID: "YOUR_CLIENT_ID",
GrantOptionSet: authentication.GrantOptionSet{
ROPCOption: &authentication.ROPCOption{
Username: "USER",
Password: "PASS",
},
},
},
},
}
for name, c := range tests {
t.Run(name, func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ctx := context.TODO()
getToken := mock_credentialplugin.NewMockInterface(ctrl)
getToken.EXPECT().
Do(ctx, c.in)
cmd := Cmd{
Root: &Root{
Logger: mock_logger.New(t),
},
GetToken: &GetToken{
GetToken: getToken,
Logger: mock_logger.New(t),
},
Logger: mock_logger.New(t),
}
exitCode := cmd.Run(ctx, c.args, version)
if exitCode != 0 {
t.Errorf("exitCode wants 0 but %d", exitCode)
}
})
}
t.Run("MissingMandatoryOptions", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ctx := context.TODO()
cmd := Cmd{
Root: &Root{
Logger: mock_logger.New(t),
},
GetToken: &GetToken{
GetToken: mock_credentialplugin.NewMockInterface(ctrl),
Logger: mock_logger.New(t),
},
Logger: mock_logger.New(t),
}
exitCode := cmd.Run(ctx, []string{executable, "get-token"}, version)
if exitCode != 1 {
t.Errorf("exitCode wants 1 but %d", exitCode)
}
})
t.Run("TooManyArgs", func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
ctx := context.TODO()
cmd := Cmd{
Root: &Root{
Logger: mock_logger.New(t),
},
GetToken: &GetToken{
GetToken: mock_credentialplugin.NewMockInterface(ctrl),
Logger: mock_logger.New(t),
},
Logger: mock_logger.New(t),
}
exitCode := cmd.Run(ctx, []string{executable, "get-token", "foo"}, version)
if exitCode != 1 {
t.Errorf("exitCode wants 1 but %d", exitCode)
}
})
})
}

View File

@@ -1,82 +0,0 @@
package cmd
import (
"context"
"github.com/int128/kubelogin/pkg/adaptors/logger"
"github.com/int128/kubelogin/pkg/usecases/credentialplugin"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"golang.org/x/xerrors"
)
// getTokenOptions represents the options for get-token command.
type getTokenOptions struct {
IssuerURL string
ClientID string
ClientSecret string
ExtraScopes []string
CertificateAuthority string
SkipTLSVerify bool
TokenCacheDir string
authenticationOptions authenticationOptions
}
func (o *getTokenOptions) register(f *pflag.FlagSet) {
f.SortFlags = false
f.StringVar(&o.IssuerURL, "oidc-issuer-url", "", "Issuer URL of the provider (mandatory)")
f.StringVar(&o.ClientID, "oidc-client-id", "", "Client ID of the provider (mandatory)")
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.StringVar(&o.CertificateAuthority, "certificate-authority", "", "Path to a cert file for the certificate authority")
f.BoolVar(&o.SkipTLSVerify, "insecure-skip-tls-verify", false, "If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure")
f.StringVar(&o.TokenCacheDir, "token-cache-dir", defaultTokenCacheDir, "Path to a directory for caching tokens")
o.authenticationOptions.register(f)
}
type GetToken struct {
GetToken credentialplugin.Interface
Logger logger.Interface
}
func (cmd *GetToken) New(ctx context.Context) *cobra.Command {
var o getTokenOptions
c := &cobra.Command{
Use: "get-token [flags]",
Short: "Run as a kubectl credential plugin",
Args: func(c *cobra.Command, args []string) error {
if err := cobra.NoArgs(c, args); err != nil {
return err
}
if o.IssuerURL == "" {
return xerrors.New("--oidc-issuer-url is missing")
}
if o.ClientID == "" {
return xerrors.New("--oidc-client-id is missing")
}
return nil
},
RunE: func(*cobra.Command, []string) error {
grantOptionSet, err := o.authenticationOptions.grantOptionSet()
if err != nil {
return xerrors.Errorf("error: %w", err)
}
in := credentialplugin.Input{
IssuerURL: o.IssuerURL,
ClientID: o.ClientID,
ClientSecret: o.ClientSecret,
ExtraScopes: o.ExtraScopes,
CACertFilename: o.CertificateAuthority,
SkipTLSVerify: o.SkipTLSVerify,
TokenCacheDir: o.TokenCacheDir,
GrantOptionSet: grantOptionSet,
}
if err := cmd.GetToken.Do(ctx, in); err != nil {
return xerrors.Errorf("error: %w", err)
}
return nil
},
}
o.register(c.Flags())
return c
}

View File

@@ -1,124 +0,0 @@
package cmd
import (
"context"
"fmt"
"strings"
"github.com/int128/kubelogin/pkg/adaptors/kubeconfig"
"github.com/int128/kubelogin/pkg/adaptors/logger"
"github.com/int128/kubelogin/pkg/usecases/authentication"
"github.com/int128/kubelogin/pkg/usecases/standalone"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"golang.org/x/xerrors"
)
const longDescription = `Login to the OpenID Connect provider.
You need to set up the OIDC provider, role binding, Kubernetes API server and kubeconfig.
Run the following command to show the setup instruction:
kubectl oidc-login setup
See https://github.com/int128/kubelogin for more.
`
// rootOptions represents the options for the root command.
type rootOptions struct {
Kubeconfig string
Context string
User string
CertificateAuthority string
SkipTLSVerify bool
authenticationOptions authenticationOptions
}
func (o *rootOptions) register(f *pflag.FlagSet) {
f.SortFlags = false
f.StringVar(&o.Kubeconfig, "kubeconfig", "", "Path to the kubeconfig file")
f.StringVar(&o.Context, "context", "", "The name of the kubeconfig context to use")
f.StringVar(&o.User, "user", "", "The name of the kubeconfig user to use. Prior to --context")
f.StringVar(&o.CertificateAuthority, "certificate-authority", "", "Path to a cert file for the certificate authority")
f.BoolVar(&o.SkipTLSVerify, "insecure-skip-tls-verify", false, "If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure")
o.authenticationOptions.register(f)
}
type authenticationOptions struct {
GrantType string
ListenPort []int
SkipOpenBrowser bool
Username string
Password string
}
var allGrantType = strings.Join([]string{
"auto",
"authcode",
"authcode-keyboard",
"password",
}, "|")
func (o *authenticationOptions) register(f *pflag.FlagSet) {
f.StringVar(&o.GrantType, "grant-type", "auto", fmt.Sprintf("The authorization grant type to use. One of (%s)", allGrantType))
f.IntSliceVar(&o.ListenPort, "listen-port", defaultListenPort, "Port to bind to the local server. If multiple ports are given, it will try the ports in order")
f.BoolVar(&o.SkipOpenBrowser, "skip-open-browser", false, "If true, it does not open the browser on authentication")
f.StringVar(&o.Username, "username", "", "If set, perform the resource owner password credentials grant")
f.StringVar(&o.Password, "password", "", "If set, use the password instead of asking it")
}
func (o *authenticationOptions) grantOptionSet() (s authentication.GrantOptionSet, err error) {
switch {
case o.GrantType == "authcode" || (o.GrantType == "auto" && o.Username == ""):
s.AuthCodeOption = &authentication.AuthCodeOption{
BindAddress: translateListenPortToBindAddress(o.ListenPort),
SkipOpenBrowser: o.SkipOpenBrowser,
}
case o.GrantType == "authcode-keyboard":
s.AuthCodeKeyboardOption = &authentication.AuthCodeKeyboardOption{}
case o.GrantType == "password" || (o.GrantType == "auto" && o.Username != ""):
s.ROPCOption = &authentication.ROPCOption{
Username: o.Username,
Password: o.Password,
}
default:
err = xerrors.Errorf("grant-type must be one of (%s)", allGrantType)
}
return
}
type Root struct {
Standalone standalone.Interface
Logger logger.Interface
}
func (cmd *Root) New(ctx context.Context, executable string) *cobra.Command {
var o rootOptions
rootCmd := &cobra.Command{
Use: executable,
Short: "Login to the OpenID Connect provider",
Long: longDescription,
Args: cobra.NoArgs,
RunE: func(*cobra.Command, []string) error {
grantOptionSet, err := o.authenticationOptions.grantOptionSet()
if err != nil {
return xerrors.Errorf("invalid option: %w", err)
}
in := standalone.Input{
KubeconfigFilename: o.Kubeconfig,
KubeconfigContext: kubeconfig.ContextName(o.Context),
KubeconfigUser: kubeconfig.UserName(o.User),
CACertFilename: o.CertificateAuthority,
SkipTLSVerify: o.SkipTLSVerify,
GrantOptionSet: grantOptionSet,
}
if err := cmd.Standalone.Do(ctx, in); err != nil {
return xerrors.Errorf("error: %w", err)
}
return nil
},
}
o.register(rootCmd.Flags())
cmd.Logger.AddFlags(rootCmd.PersistentFlags())
return rootCmd
}

View File

@@ -1,51 +0,0 @@
// Package credentialplugin provides interaction with kubectl for a credential plugin.
package credentialplugin
import (
"encoding/json"
"os"
"time"
"github.com/google/wire"
"golang.org/x/xerrors"
"k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
)
//go:generate mockgen -destination mock_credentialplugin/mock_credentialplugin.go github.com/int128/kubelogin/pkg/adaptors/credentialplugin Interface
var Set = wire.NewSet(
wire.Struct(new(Interaction), "*"),
wire.Bind(new(Interface), new(*Interaction)),
)
type Interface interface {
Write(out Output) error
}
// Output represents an output object of the credential plugin.
type Output struct {
Token string
Expiry time.Time
}
type Interaction struct{}
// Write writes the ExecCredential to standard output for kubectl.
func (*Interaction) Write(out Output) error {
ec := &v1beta1.ExecCredential{
TypeMeta: v1.TypeMeta{
APIVersion: "client.authentication.k8s.io/v1beta1",
Kind: "ExecCredential",
},
Status: &v1beta1.ExecCredentialStatus{
Token: out.Token,
ExpirationTimestamp: &v1.Time{Time: out.Expiry},
},
}
e := json.NewEncoder(os.Stdout)
if err := e.Encode(ec); err != nil {
return xerrors.Errorf("could not write the ExecCredential: %w", err)
}
return nil
}

View File

@@ -1,48 +0,0 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/int128/kubelogin/pkg/adaptors/credentialplugin (interfaces: Interface)
// Package mock_credentialplugin is a generated GoMock package.
package mock_credentialplugin
import (
gomock "github.com/golang/mock/gomock"
credentialplugin "github.com/int128/kubelogin/pkg/adaptors/credentialplugin"
reflect "reflect"
)
// MockInterface is a mock of Interface interface
type MockInterface struct {
ctrl *gomock.Controller
recorder *MockInterfaceMockRecorder
}
// MockInterfaceMockRecorder is the mock recorder for MockInterface
type MockInterfaceMockRecorder struct {
mock *MockInterface
}
// NewMockInterface creates a new mock instance
func NewMockInterface(ctrl *gomock.Controller) *MockInterface {
mock := &MockInterface{ctrl: ctrl}
mock.recorder = &MockInterfaceMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder {
return m.recorder
}
// Write mocks base method
func (m *MockInterface) Write(arg0 credentialplugin.Output) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Write", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// Write indicates an expected call of Write
func (mr *MockInterfaceMockRecorder) Write(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Write", reflect.TypeOf((*MockInterface)(nil).Write), arg0)
}

View File

@@ -1,76 +0,0 @@
// Package env provides environment dependent facilities.
package env
import (
"bufio"
"fmt"
"os"
"strings"
"syscall"
"github.com/google/wire"
"github.com/pkg/browser"
"golang.org/x/crypto/ssh/terminal"
"golang.org/x/xerrors"
)
//go:generate mockgen -destination mock_env/mock_env.go github.com/int128/kubelogin/pkg/adaptors/env Interface
func init() {
// In credential plugin mode, some browser launcher writes a message to stdout
// and it may break the credential json for client-go.
// This prevents the browser launcher from breaking the credential json.
browser.Stdout = os.Stderr
}
// Set provides an implementation and interface for Env.
var Set = wire.NewSet(
wire.Struct(new(Env), "*"),
wire.Bind(new(Interface), new(*Env)),
)
type Interface interface {
ReadString(prompt string) (string, error)
ReadPassword(prompt string) (string, error)
OpenBrowser(url string) error
}
// Env provides environment specific facilities.
type Env struct{}
// ReadString reads a string from the stdin.
func (*Env) ReadString(prompt string) (string, error) {
if _, err := fmt.Fprint(os.Stderr, prompt); err != nil {
return "", xerrors.Errorf("could not write the prompt: %w", err)
}
r := bufio.NewReader(os.Stdin)
s, err := r.ReadString('\n')
if err != nil {
return "", xerrors.Errorf("could not read from stdin: %w", err)
}
s = strings.TrimRight(s, "\r\n")
return s, nil
}
// ReadPassword reads a password from the stdin without echo back.
func (*Env) ReadPassword(prompt string) (string, error) {
if _, err := fmt.Fprint(os.Stderr, prompt); err != nil {
return "", xerrors.Errorf("could not write the prompt: %w", err)
}
b, err := terminal.ReadPassword(int(syscall.Stdin))
if err != nil {
return "", xerrors.Errorf("could not read from stdin: %w", err)
}
if _, err := fmt.Fprintln(os.Stderr); err != nil {
return "", xerrors.Errorf("could not write a new line: %w", err)
}
return string(b), nil
}
// OpenBrowser opens the default browser.
func (env *Env) OpenBrowser(url string) error {
if err := browser.OpenURL(url); err != nil {
return xerrors.Errorf("could not open the browser: %w", err)
}
return nil
}

View File

@@ -1,77 +0,0 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/int128/kubelogin/pkg/adaptors/env (interfaces: Interface)
// Package mock_env is a generated GoMock package.
package mock_env
import (
gomock "github.com/golang/mock/gomock"
reflect "reflect"
)
// MockInterface is a mock of Interface interface
type MockInterface struct {
ctrl *gomock.Controller
recorder *MockInterfaceMockRecorder
}
// MockInterfaceMockRecorder is the mock recorder for MockInterface
type MockInterfaceMockRecorder struct {
mock *MockInterface
}
// NewMockInterface creates a new mock instance
func NewMockInterface(ctrl *gomock.Controller) *MockInterface {
mock := &MockInterface{ctrl: ctrl}
mock.recorder = &MockInterfaceMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder {
return m.recorder
}
// OpenBrowser mocks base method
func (m *MockInterface) OpenBrowser(arg0 string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "OpenBrowser", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// OpenBrowser indicates an expected call of OpenBrowser
func (mr *MockInterfaceMockRecorder) OpenBrowser(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OpenBrowser", reflect.TypeOf((*MockInterface)(nil).OpenBrowser), arg0)
}
// ReadPassword mocks base method
func (m *MockInterface) ReadPassword(arg0 string) (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ReadPassword", arg0)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ReadPassword indicates an expected call of ReadPassword
func (mr *MockInterfaceMockRecorder) ReadPassword(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadPassword", reflect.TypeOf((*MockInterface)(nil).ReadPassword), arg0)
}
// ReadString mocks base method
func (m *MockInterface) ReadString(arg0 string) (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ReadString", arg0)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ReadString indicates an expected call of ReadString
func (mr *MockInterfaceMockRecorder) ReadString(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadString", reflect.TypeOf((*MockInterface)(nil).ReadString), arg0)
}

View File

@@ -1,74 +0,0 @@
// Package jwtdecoder provides decoding a JWT.
package jwtdecoder
import (
"bytes"
"encoding/json"
"fmt"
"strings"
"time"
"github.com/dgrijalva/jwt-go"
"github.com/google/wire"
"golang.org/x/xerrors"
)
//go:generate mockgen -destination mock_jwtdecoder/mock_jwtdecoder.go github.com/int128/kubelogin/pkg/adaptors/jwtdecoder Interface
// Set provides an implementation and interface.
var Set = wire.NewSet(
wire.Struct(new(Decoder), "*"),
wire.Bind(new(Interface), new(*Decoder)),
)
type Interface interface {
Decode(s string) (*Claims, error)
}
// Claims represents claims of a token.
type Claims struct {
Subject string
Expiry time.Time
Pretty map[string]string // string representation for debug and logging
}
type Decoder struct{}
// Decode returns the claims of the JWT.
// Note that this method does not verify the signature and always trust it.
func (d *Decoder) Decode(s string) (*Claims, error) {
parts := strings.Split(s, ".")
if len(parts) != 3 {
return nil, xerrors.Errorf("token contains an invalid number of segments")
}
b, err := jwt.DecodeSegment(parts[1])
if err != nil {
return nil, xerrors.Errorf("could not decode the token: %w", err)
}
var claims jwt.StandardClaims
if err := json.NewDecoder(bytes.NewBuffer(b)).Decode(&claims); err != nil {
return nil, xerrors.Errorf("could not decode the json of token: %w", err)
}
var rawClaims map[string]interface{}
if err := json.NewDecoder(bytes.NewBuffer(b)).Decode(&rawClaims); err != nil {
return nil, xerrors.Errorf("could not decode the json of token: %w", err)
}
return &Claims{
Subject: claims.Subject,
Expiry: time.Unix(claims.ExpiresAt, 0),
Pretty: dumpRawClaims(rawClaims),
}, nil
}
func dumpRawClaims(rawClaims map[string]interface{}) map[string]string {
claims := make(map[string]string)
for k, v := range rawClaims {
switch v := v.(type) {
case float64:
claims[k] = fmt.Sprintf("%.f", v)
default:
claims[k] = fmt.Sprintf("%v", v)
}
}
return claims
}

View File

@@ -1,87 +0,0 @@
package jwtdecoder
import (
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"io/ioutil"
"testing"
"time"
"github.com/dgrijalva/jwt-go"
)
func TestDecoder_Decode(t *testing.T) {
var decoder Decoder
t.Run("ValidToken", func(t *testing.T) {
expiry := time.Now().Round(time.Second)
idToken := newIDToken(t, "https://issuer.example.com", expiry)
decodedToken, err := decoder.Decode(idToken)
if err != nil {
t.Fatalf("Decode error: %s", err)
}
if decodedToken.Expiry != expiry {
t.Errorf("Expiry wants %s but %s", expiry, decodedToken.Expiry)
}
t.Logf("Pretty=%+v", decodedToken.Pretty)
})
t.Run("InvalidToken", func(t *testing.T) {
decodedToken, err := decoder.Decode("HEADER.INVALID_TOKEN.SIGNATURE")
if err == nil {
t.Errorf("error wants non-nil but nil")
} else {
t.Logf("expected error: %+v", err)
}
if decodedToken != nil {
t.Errorf("decodedToken wants nil but %+v", decodedToken)
}
})
}
func newIDToken(t *testing.T, issuer string, expiry time.Time) string {
t.Helper()
claims := struct {
jwt.StandardClaims
Nonce string `json:"nonce"`
Groups []string `json:"groups"`
EmailVerified bool `json:"email_verified"`
}{
StandardClaims: jwt.StandardClaims{
Issuer: issuer,
Audience: "kubernetes",
Subject: "SUBJECT",
IssuedAt: time.Now().Unix(),
ExpiresAt: expiry.Unix(),
},
Nonce: "NONCE",
Groups: []string{"admin", "users"},
EmailVerified: false,
}
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
s, err := token.SignedString(readPrivateKey(t, "testdata/jws.key"))
if err != nil {
t.Fatalf("Could not sign the claims: %s", err)
}
return s
}
func readPrivateKey(t *testing.T, name string) *rsa.PrivateKey {
t.Helper()
b, err := ioutil.ReadFile(name)
if err != nil {
t.Fatalf("could not read the file: %s", err)
}
block, rest := pem.Decode(b)
if block == nil {
t.Fatalf("could not decode PEM")
}
if len(rest) > 0 {
t.Fatalf("PEM should contain single key but multiple keys")
}
k, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
t.Fatalf("could not parse the key: %s", err)
}
return k
}

View File

@@ -1,49 +0,0 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/int128/kubelogin/pkg/adaptors/jwtdecoder (interfaces: Interface)
// Package mock_jwtdecoder is a generated GoMock package.
package mock_jwtdecoder
import (
gomock "github.com/golang/mock/gomock"
jwtdecoder "github.com/int128/kubelogin/pkg/adaptors/jwtdecoder"
reflect "reflect"
)
// MockInterface is a mock of Interface interface
type MockInterface struct {
ctrl *gomock.Controller
recorder *MockInterfaceMockRecorder
}
// MockInterfaceMockRecorder is the mock recorder for MockInterface
type MockInterfaceMockRecorder struct {
mock *MockInterface
}
// NewMockInterface creates a new mock instance
func NewMockInterface(ctrl *gomock.Controller) *MockInterface {
mock := &MockInterface{ctrl: ctrl}
mock.recorder = &MockInterfaceMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder {
return m.recorder
}
// Decode mocks base method
func (m *MockInterface) Decode(arg0 string) (*jwtdecoder.Claims, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Decode", arg0)
ret0, _ := ret[0].(*jwtdecoder.Claims)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Decode indicates an expected call of Decode
func (mr *MockInterfaceMockRecorder) Decode(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Decode", reflect.TypeOf((*MockInterface)(nil).Decode), arg0)
}

View File

@@ -1,8 +0,0 @@
all: jws.key
jws.key:
openssl genrsa -out $@ 1024
.PHONY: clean
clean:
-rm -v jws.key

View File

@@ -1,15 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCrH34yA/f/sBOUlkYnRtd2jgDZ3WivhidqvoQaa73xqTazbkn6
GZ9r7jx0CGLRV2bmErj2WoyT54yrhezrKh0YXAHlrwLdsmV4dwiV0lOfUJd9P/vF
e2hiAWv4CcO9ZuNkTsrxM5W8Wdj2tjqOvsIn4We+HWPkpknT7VtT5RrumwIDAQAB
AoGAFqy5oA7+kZbXQV0YNqQgcMkoO7Ym5Ps1xeMwxf94z8jIQsZebxFuGnMa95UU
4wBd1ias85fUANUxwpigaBjQee5Hk+dnfUe1snUWYNm9H6tKrXEF8ajer3a2knEv
GfK0CSEumFougfW2xG88ChGTS60wc+MIRfXERCvWpGm/5EECQQDdv5IBSi89g/R1
5AGZKFCoqr6Zw5bWEKPzCCYJZzncR1ER9vP2AnMExM8Io/87WYvmpZIUrXJvQYm8
hkfVOcBZAkEAxY4VcqmRWru3zmnbj21MwcwtgESaONkWsHeYs1C/Y/3zt7TuelYz
ZJ9aUuUsaiJLEs9Y26nMt0L0snWGr2noEwJBANaDp1PWFyMUTt3pB17JcFXqb15C
pt1I1cGapWk9Uez1lMijNNhNAEWhuoKqW5Nnif5DN7EHJYfZR8x3vm/YYWkCQHAA
0iAkCwjKDLe2RIjYiwAE5ncmbdl1GuwJokVnrlrei+LHbb1mSdTuk6MT006JCs8r
R1GivzHXgCv9fdLN1IkCQHxRvv9RPND80eEkdMv4qu0s22OLRhLQ/pb+YeT5Cjjv
pJYWKrvXdRZcuNde9JiiTgK2UW1wM8KeD/EGvK2yF6M=
-----END RSA PRIVATE KEY-----

View File

@@ -1,63 +0,0 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/int128/kubelogin/pkg/adaptors/kubeconfig (interfaces: Interface)
// Package mock_kubeconfig is a generated GoMock package.
package mock_kubeconfig
import (
gomock "github.com/golang/mock/gomock"
kubeconfig "github.com/int128/kubelogin/pkg/adaptors/kubeconfig"
reflect "reflect"
)
// MockInterface is a mock of Interface interface
type MockInterface struct {
ctrl *gomock.Controller
recorder *MockInterfaceMockRecorder
}
// MockInterfaceMockRecorder is the mock recorder for MockInterface
type MockInterfaceMockRecorder struct {
mock *MockInterface
}
// NewMockInterface creates a new mock instance
func NewMockInterface(ctrl *gomock.Controller) *MockInterface {
mock := &MockInterface{ctrl: ctrl}
mock.recorder = &MockInterfaceMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder {
return m.recorder
}
// GetCurrentAuthProvider mocks base method
func (m *MockInterface) GetCurrentAuthProvider(arg0 string, arg1 kubeconfig.ContextName, arg2 kubeconfig.UserName) (*kubeconfig.AuthProvider, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetCurrentAuthProvider", arg0, arg1, arg2)
ret0, _ := ret[0].(*kubeconfig.AuthProvider)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetCurrentAuthProvider indicates an expected call of GetCurrentAuthProvider
func (mr *MockInterfaceMockRecorder) GetCurrentAuthProvider(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCurrentAuthProvider", reflect.TypeOf((*MockInterface)(nil).GetCurrentAuthProvider), arg0, arg1, arg2)
}
// UpdateAuthProvider mocks base method
func (m *MockInterface) UpdateAuthProvider(arg0 *kubeconfig.AuthProvider) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UpdateAuthProvider", arg0)
ret0, _ := ret[0].(error)
return ret0
}
// UpdateAuthProvider indicates an expected call of UpdateAuthProvider
func (mr *MockInterfaceMockRecorder) UpdateAuthProvider(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAuthProvider", reflect.TypeOf((*MockInterface)(nil).UpdateAuthProvider), arg0)
}

View File

@@ -1,46 +0,0 @@
package mock_logger
import (
"fmt"
"github.com/int128/kubelogin/pkg/adaptors/logger"
"github.com/spf13/pflag"
)
func New(t testingLogger) *Logger {
return &Logger{t}
}
type testingLogger interface {
Logf(format string, v ...interface{})
}
// Logger provides logging facility using testing.T.
type Logger struct {
t testingLogger
}
func (*Logger) AddFlags(f *pflag.FlagSet) {
f.IntP("v", "v", 0, "dummy flag used in the tests")
}
func (l *Logger) Printf(format string, args ...interface{}) {
l.t.Logf(format, args...)
}
type Verbose struct {
t testingLogger
level int
}
func (v *Verbose) Infof(format string, args ...interface{}) {
v.t.Logf(fmt.Sprintf("I%d] ", v.level)+format, args...)
}
func (l *Logger) V(level int) logger.Verbose {
return &Verbose{l.t, level}
}
func (*Logger) IsEnabled(level int) bool {
return true
}

View File

@@ -1,68 +0,0 @@
// Package oidcclient provides a client of OpenID Connect.
package oidcclient
import (
"context"
"crypto/tls"
"net/http"
"github.com/coreos/go-oidc"
"github.com/int128/kubelogin/pkg/adaptors/certpool"
"github.com/int128/kubelogin/pkg/adaptors/logger"
"github.com/int128/kubelogin/pkg/adaptors/oidcclient/logging"
"golang.org/x/oauth2"
"golang.org/x/xerrors"
)
type FactoryInterface interface {
New(ctx context.Context, config Config) (Interface, error)
}
// Config represents a configuration of OpenID Connect client.
type Config struct {
IssuerURL string
ClientID string
ClientSecret string
ExtraScopes []string // optional
CertPool certpool.Interface
SkipTLSVerify bool
}
type Factory struct {
Logger logger.Interface
}
// New returns an instance of adaptors.Interface with the given configuration.
func (f *Factory) New(ctx context.Context, config Config) (Interface, error) {
var tlsConfig tls.Config
tlsConfig.InsecureSkipVerify = config.SkipTLSVerify
config.CertPool.SetRootCAs(&tlsConfig)
baseTransport := &http.Transport{
TLSClientConfig: &tlsConfig,
Proxy: http.ProxyFromEnvironment,
}
loggingTransport := &logging.Transport{
Base: baseTransport,
Logger: f.Logger,
}
httpClient := &http.Client{
Transport: loggingTransport,
}
ctx = context.WithValue(ctx, oauth2.HTTPClient, httpClient)
provider, err := oidc.NewProvider(ctx, config.IssuerURL)
if err != nil {
return nil, xerrors.Errorf("could not discovery the OIDCClientFactory issuer: %w", err)
}
return &client{
httpClient: httpClient,
provider: provider,
oauth2Config: oauth2.Config{
Endpoint: provider.Endpoint(),
ClientID: config.ClientID,
ClientSecret: config.ClientSecret,
Scopes: append(config.ExtraScopes, oidc.ScopeOpenID),
},
logger: f.Logger,
}, nil
}

View File

@@ -1,147 +0,0 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/int128/kubelogin/pkg/adaptors/oidcclient (interfaces: FactoryInterface,Interface)
// Package mock_oidcclient is a generated GoMock package.
package mock_oidcclient
import (
context "context"
gomock "github.com/golang/mock/gomock"
oidcclient "github.com/int128/kubelogin/pkg/adaptors/oidcclient"
reflect "reflect"
)
// MockFactoryInterface is a mock of FactoryInterface interface
type MockFactoryInterface struct {
ctrl *gomock.Controller
recorder *MockFactoryInterfaceMockRecorder
}
// MockFactoryInterfaceMockRecorder is the mock recorder for MockFactoryInterface
type MockFactoryInterfaceMockRecorder struct {
mock *MockFactoryInterface
}
// NewMockFactoryInterface creates a new mock instance
func NewMockFactoryInterface(ctrl *gomock.Controller) *MockFactoryInterface {
mock := &MockFactoryInterface{ctrl: ctrl}
mock.recorder = &MockFactoryInterfaceMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockFactoryInterface) EXPECT() *MockFactoryInterfaceMockRecorder {
return m.recorder
}
// New mocks base method
func (m *MockFactoryInterface) New(arg0 context.Context, arg1 oidcclient.Config) (oidcclient.Interface, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "New", arg0, arg1)
ret0, _ := ret[0].(oidcclient.Interface)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// New indicates an expected call of New
func (mr *MockFactoryInterfaceMockRecorder) New(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "New", reflect.TypeOf((*MockFactoryInterface)(nil).New), arg0, arg1)
}
// MockInterface is a mock of Interface interface
type MockInterface struct {
ctrl *gomock.Controller
recorder *MockInterfaceMockRecorder
}
// MockInterfaceMockRecorder is the mock recorder for MockInterface
type MockInterfaceMockRecorder struct {
mock *MockInterface
}
// NewMockInterface creates a new mock instance
func NewMockInterface(ctrl *gomock.Controller) *MockInterface {
mock := &MockInterface{ctrl: ctrl}
mock.recorder = &MockInterfaceMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder {
return m.recorder
}
// ExchangeAuthCode mocks base method
func (m *MockInterface) ExchangeAuthCode(arg0 context.Context, arg1 oidcclient.ExchangeAuthCodeInput) (*oidcclient.TokenSet, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ExchangeAuthCode", arg0, arg1)
ret0, _ := ret[0].(*oidcclient.TokenSet)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ExchangeAuthCode indicates an expected call of ExchangeAuthCode
func (mr *MockInterfaceMockRecorder) ExchangeAuthCode(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExchangeAuthCode", reflect.TypeOf((*MockInterface)(nil).ExchangeAuthCode), arg0, arg1)
}
// GetAuthCodeURL mocks base method
func (m *MockInterface) GetAuthCodeURL(arg0 oidcclient.AuthCodeURLInput) string {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetAuthCodeURL", arg0)
ret0, _ := ret[0].(string)
return ret0
}
// GetAuthCodeURL indicates an expected call of GetAuthCodeURL
func (mr *MockInterfaceMockRecorder) GetAuthCodeURL(arg0 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthCodeURL", reflect.TypeOf((*MockInterface)(nil).GetAuthCodeURL), arg0)
}
// GetTokenByAuthCode mocks base method
func (m *MockInterface) GetTokenByAuthCode(arg0 context.Context, arg1 oidcclient.GetTokenByAuthCodeInput, arg2 chan<- string) (*oidcclient.TokenSet, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetTokenByAuthCode", arg0, arg1, arg2)
ret0, _ := ret[0].(*oidcclient.TokenSet)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetTokenByAuthCode indicates an expected call of GetTokenByAuthCode
func (mr *MockInterfaceMockRecorder) GetTokenByAuthCode(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTokenByAuthCode", reflect.TypeOf((*MockInterface)(nil).GetTokenByAuthCode), arg0, arg1, arg2)
}
// GetTokenByROPC mocks base method
func (m *MockInterface) GetTokenByROPC(arg0 context.Context, arg1, arg2 string) (*oidcclient.TokenSet, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetTokenByROPC", arg0, arg1, arg2)
ret0, _ := ret[0].(*oidcclient.TokenSet)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetTokenByROPC indicates an expected call of GetTokenByROPC
func (mr *MockInterfaceMockRecorder) GetTokenByROPC(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTokenByROPC", reflect.TypeOf((*MockInterface)(nil).GetTokenByROPC), arg0, arg1, arg2)
}
// Refresh mocks base method
func (m *MockInterface) Refresh(arg0 context.Context, arg1 string) (*oidcclient.TokenSet, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Refresh", arg0, arg1)
ret0, _ := ret[0].(*oidcclient.TokenSet)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Refresh indicates an expected call of Refresh
func (mr *MockInterfaceMockRecorder) Refresh(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Refresh", reflect.TypeOf((*MockInterface)(nil).Refresh), arg0, arg1)
}

View File

@@ -1,197 +0,0 @@
package oidcclient
import (
"context"
"fmt"
"net/http"
"time"
"github.com/coreos/go-oidc"
"github.com/google/wire"
"github.com/int128/kubelogin/pkg/adaptors/logger"
"github.com/int128/oauth2cli"
"golang.org/x/oauth2"
"golang.org/x/xerrors"
)
//go:generate mockgen -destination mock_oidcclient/mock_oidcclient.go github.com/int128/kubelogin/pkg/adaptors/oidcclient FactoryInterface,Interface
// Set provides an implementation and interface for OIDC.
var Set = wire.NewSet(
wire.Struct(new(Factory), "*"),
wire.Bind(new(FactoryInterface), new(*Factory)),
)
type Interface interface {
GetAuthCodeURL(in AuthCodeURLInput) string
ExchangeAuthCode(ctx context.Context, in ExchangeAuthCodeInput) (*TokenSet, error)
GetTokenByAuthCode(ctx context.Context, in GetTokenByAuthCodeInput, localServerReadyChan chan<- string) (*TokenSet, error)
GetTokenByROPC(ctx context.Context, username, password string) (*TokenSet, error)
Refresh(ctx context.Context, refreshToken string) (*TokenSet, error)
}
type AuthCodeURLInput struct {
State string
Nonce string
CodeChallenge string
CodeChallengeMethod string
RedirectURI string
}
type ExchangeAuthCodeInput struct {
Code string
CodeVerifier string
Nonce string
RedirectURI string
}
type GetTokenByAuthCodeInput struct {
BindAddress []string
Nonce string
CodeChallenge string
CodeChallengeMethod string
CodeVerifier string
}
// TokenSet represents an output DTO of
// Interface.GetTokenByAuthCode, Interface.GetTokenByROPC and Interface.Refresh.
type TokenSet struct {
IDToken string
RefreshToken string
IDTokenSubject string
IDTokenExpiry time.Time
IDTokenClaims map[string]string // string representation of claims for logging
}
type client struct {
httpClient *http.Client
provider *oidc.Provider
oauth2Config oauth2.Config
logger logger.Interface
}
func (c *client) wrapContext(ctx context.Context) context.Context {
if c.httpClient != nil {
ctx = context.WithValue(ctx, oauth2.HTTPClient, c.httpClient)
}
return ctx
}
// GetTokenByAuthCode performs the authorization code flow.
func (c *client) GetTokenByAuthCode(ctx context.Context, in GetTokenByAuthCodeInput, localServerReadyChan chan<- string) (*TokenSet, error) {
ctx = c.wrapContext(ctx)
config := oauth2cli.Config{
OAuth2Config: c.oauth2Config,
AuthCodeOptions: []oauth2.AuthCodeOption{
oauth2.AccessTypeOffline,
oidc.Nonce(in.Nonce),
oauth2.SetAuthURLParam("code_challenge", in.CodeChallenge),
oauth2.SetAuthURLParam("code_challenge_method", in.CodeChallengeMethod),
},
TokenRequestOptions: []oauth2.AuthCodeOption{
oauth2.SetAuthURLParam("code_verifier", in.CodeVerifier),
},
LocalServerBindAddress: in.BindAddress,
LocalServerReadyChan: localServerReadyChan,
}
token, err := oauth2cli.GetToken(ctx, config)
if err != nil {
return nil, xerrors.Errorf("could not get a token: %w", err)
}
return c.verifyToken(ctx, token, in.Nonce)
}
// GetAuthCodeURL returns the URL of authentication request for the authorization code flow.
func (c *client) GetAuthCodeURL(in AuthCodeURLInput) string {
cfg := c.oauth2Config
cfg.RedirectURL = in.RedirectURI
return cfg.AuthCodeURL(in.State,
oauth2.AccessTypeOffline,
oidc.Nonce(in.Nonce),
oauth2.SetAuthURLParam("code_challenge", in.CodeChallenge),
oauth2.SetAuthURLParam("code_challenge_method", in.CodeChallengeMethod),
)
}
// ExchangeAuthCode exchanges the authorization code and token.
func (c *client) ExchangeAuthCode(ctx context.Context, in ExchangeAuthCodeInput) (*TokenSet, error) {
ctx = c.wrapContext(ctx)
cfg := c.oauth2Config
cfg.RedirectURL = in.RedirectURI
token, err := cfg.Exchange(ctx, in.Code, oauth2.SetAuthURLParam("code_verifier", in.CodeVerifier))
if err != nil {
return nil, xerrors.Errorf("could not exchange the authorization code: %w", err)
}
return c.verifyToken(ctx, token, in.Nonce)
}
// GetTokenByROPC performs the resource owner password credentials flow.
func (c *client) GetTokenByROPC(ctx context.Context, username, password string) (*TokenSet, error) {
ctx = c.wrapContext(ctx)
token, err := c.oauth2Config.PasswordCredentialsToken(ctx, username, password)
if err != nil {
return nil, xerrors.Errorf("could not get a token: %w", err)
}
return c.verifyToken(ctx, token, "")
}
// Refresh sends a refresh token request and returns a token set.
func (c *client) Refresh(ctx context.Context, refreshToken string) (*TokenSet, error) {
ctx = c.wrapContext(ctx)
currentToken := &oauth2.Token{
Expiry: time.Now(),
RefreshToken: refreshToken,
}
source := c.oauth2Config.TokenSource(ctx, currentToken)
token, err := source.Token()
if err != nil {
return nil, xerrors.Errorf("could not refresh the token: %w", err)
}
return c.verifyToken(ctx, token, "")
}
// verifyToken verifies the token with the certificates of the provider and the nonce.
// If the nonce is an empty string, it does not verify the nonce.
func (c *client) verifyToken(ctx context.Context, token *oauth2.Token, nonce string) (*TokenSet, error) {
idTokenString, ok := token.Extra("id_token").(string)
if !ok {
return nil, xerrors.Errorf("id_token is missing in the token response: %s", token)
}
verifier := c.provider.Verifier(&oidc.Config{ClientID: c.oauth2Config.ClientID})
idToken, err := verifier.Verify(ctx, idTokenString)
if err != nil {
return nil, xerrors.Errorf("could not verify the ID token: %w", err)
}
if nonce != "" && nonce != idToken.Nonce {
return nil, xerrors.Errorf("nonce did not match (wants %s but was %s)", nonce, idToken.Nonce)
}
claims, err := dumpClaims(idToken)
if err != nil {
c.logger.V(1).Infof("incomplete claims of the ID token: %w", err)
}
return &TokenSet{
IDToken: idTokenString,
RefreshToken: token.RefreshToken,
IDTokenExpiry: idToken.Expiry,
IDTokenClaims: claims,
}, nil
}
func dumpClaims(token *oidc.IDToken) (map[string]string, error) {
var rawClaims map[string]interface{}
err := token.Claims(&rawClaims)
return dumpRawClaims(rawClaims), err
}
func dumpRawClaims(rawClaims map[string]interface{}) map[string]string {
claims := make(map[string]string)
for k, v := range rawClaims {
switch v := v.(type) {
case float64:
claims[k] = fmt.Sprintf("%.f", v)
default:
claims[k] = fmt.Sprintf("%v", v)
}
}
return claims
}

View File

@@ -1,63 +0,0 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/int128/kubelogin/pkg/adaptors/tokencache (interfaces: Interface)
// Package mock_tokencache is a generated GoMock package.
package mock_tokencache
import (
gomock "github.com/golang/mock/gomock"
tokencache "github.com/int128/kubelogin/pkg/adaptors/tokencache"
reflect "reflect"
)
// MockInterface is a mock of Interface interface
type MockInterface struct {
ctrl *gomock.Controller
recorder *MockInterfaceMockRecorder
}
// MockInterfaceMockRecorder is the mock recorder for MockInterface
type MockInterfaceMockRecorder struct {
mock *MockInterface
}
// NewMockInterface creates a new mock instance
func NewMockInterface(ctrl *gomock.Controller) *MockInterface {
mock := &MockInterface{ctrl: ctrl}
mock.recorder = &MockInterfaceMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use
func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder {
return m.recorder
}
// FindByKey mocks base method
func (m *MockInterface) FindByKey(arg0 string, arg1 tokencache.Key) (*tokencache.TokenCache, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindByKey", arg0, arg1)
ret0, _ := ret[0].(*tokencache.TokenCache)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// FindByKey indicates an expected call of FindByKey
func (mr *MockInterfaceMockRecorder) FindByKey(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindByKey", reflect.TypeOf((*MockInterface)(nil).FindByKey), arg0, arg1)
}
// Save mocks base method
func (m *MockInterface) Save(arg0 string, arg1 tokencache.Key, arg2 tokencache.TokenCache) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Save", arg0, arg1, arg2)
ret0, _ := ret[0].(error)
return ret0
}
// Save indicates an expected call of Save
func (mr *MockInterfaceMockRecorder) Save(arg0, arg1, arg2 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Save", reflect.TypeOf((*MockInterface)(nil).Save), arg0, arg1, arg2)
}

View File

@@ -1,81 +0,0 @@
package tokencache
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"os"
"path/filepath"
"github.com/google/wire"
"golang.org/x/xerrors"
)
//go:generate mockgen -destination mock_tokencache/mock_tokencache.go github.com/int128/kubelogin/pkg/adaptors/tokencache Interface
// Set provides an implementation and interface for Kubeconfig.
var Set = wire.NewSet(
wire.Struct(new(Repository), "*"),
wire.Bind(new(Interface), new(*Repository)),
)
type Interface interface {
FindByKey(dir string, key Key) (*TokenCache, error)
Save(dir string, key Key, cache TokenCache) error
}
// Key represents a key of a token cache.
type Key struct {
IssuerURL string
ClientID string
}
// TokenCache represents a token cache.
type TokenCache struct {
IDToken string `json:"id_token,omitempty"`
RefreshToken string `json:"refresh_token,omitempty"`
}
// Repository provides access to the token cache on the local filesystem.
// Filename of a token cache is sha256 digest of the issuer, zero-character and client ID.
type Repository struct{}
func (r *Repository) FindByKey(dir string, key Key) (*TokenCache, error) {
filename := filepath.Join(dir, computeFilename(key))
f, err := os.Open(filename)
if err != nil {
return nil, xerrors.Errorf("could not open file %s: %w", filename, err)
}
defer f.Close()
d := json.NewDecoder(f)
var c TokenCache
if err := d.Decode(&c); err != nil {
return nil, xerrors.Errorf("could not decode json file %s: %w", filename, err)
}
return &c, nil
}
func (r *Repository) Save(dir string, key Key, cache TokenCache) error {
if err := os.MkdirAll(dir, 0700); err != nil {
return xerrors.Errorf("could not create directory %s: %w", dir, err)
}
filename := filepath.Join(dir, computeFilename(key))
f, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return xerrors.Errorf("could not create file %s: %w", filename, err)
}
defer f.Close()
e := json.NewEncoder(f)
if err := e.Encode(&cache); err != nil {
return xerrors.Errorf("could not encode json to file %s: %w", filename, err)
}
return nil
}
func computeFilename(key Key) string {
s := sha256.New()
_, _ = s.Write([]byte(key.IssuerURL))
_, _ = s.Write([]byte{0x00})
_, _ = s.Write([]byte(key.ClientID))
return hex.EncodeToString(s.Sum(nil))
}

View File

@@ -1,80 +0,0 @@
package tokencache
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
"github.com/go-test/deep"
)
func TestRepository_FindByKey(t *testing.T) {
var r Repository
t.Run("Success", func(t *testing.T) {
dir, err := ioutil.TempDir("", "kube")
if err != nil {
t.Fatalf("could not create a temp dir: %s", err)
}
defer func() {
if err := os.RemoveAll(dir); err != nil {
t.Errorf("could not clean up the temp dir: %s", err)
}
}()
key := Key{
IssuerURL: "YOUR_ISSUER",
ClientID: "YOUR_CLIENT_ID",
}
json := `{"id_token":"YOUR_ID_TOKEN","refresh_token":"YOUR_REFRESH_TOKEN"}`
filename := filepath.Join(dir, computeFilename(key))
if err := ioutil.WriteFile(filename, []byte(json), 0600); err != nil {
t.Fatalf("could not write to the temp file: %s", err)
}
tokenCache, err := r.FindByKey(dir, key)
if err != nil {
t.Errorf("err wants nil but %+v", err)
}
want := &TokenCache{IDToken: "YOUR_ID_TOKEN", RefreshToken: "YOUR_REFRESH_TOKEN"}
if diff := deep.Equal(tokenCache, want); diff != nil {
t.Error(diff)
}
})
}
func TestRepository_Save(t *testing.T) {
var r Repository
t.Run("Success", func(t *testing.T) {
dir, err := ioutil.TempDir("", "kube")
if err != nil {
t.Fatalf("could not create a temp dir: %s", err)
}
defer func() {
if err := os.RemoveAll(dir); err != nil {
t.Errorf("could not clean up the temp dir: %s", err)
}
}()
key := Key{
IssuerURL: "YOUR_ISSUER",
ClientID: "YOUR_CLIENT_ID",
}
tokenCache := TokenCache{IDToken: "YOUR_ID_TOKEN", RefreshToken: "YOUR_REFRESH_TOKEN"}
if err := r.Save(dir, key, tokenCache); err != nil {
t.Errorf("err wants nil but %+v", err)
}
filename := filepath.Join(dir, computeFilename(key))
b, err := ioutil.ReadFile(filename)
if err != nil {
t.Fatalf("could not read the token cache file: %s", err)
}
want := `{"id_token":"YOUR_ID_TOKEN","refresh_token":"YOUR_REFRESH_TOKEN"}
`
if diff := deep.Equal(string(b), want); diff != nil {
t.Error(diff)
}
})
}

116
pkg/cmd/authentication.go Normal file
View File

@@ -0,0 +1,116 @@
package cmd
import (
"fmt"
"strings"
"time"
"github.com/int128/kubelogin/pkg/usecases/authentication"
"github.com/int128/kubelogin/pkg/usecases/authentication/authcode"
"github.com/int128/kubelogin/pkg/usecases/authentication/devicecode"
"github.com/int128/kubelogin/pkg/usecases/authentication/ropc"
"github.com/spf13/pflag"
)
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
LocalServerCertFile string
LocalServerKeyFile string
OpenURLAfterAuthentication string
RedirectURLHostname string
RedirectURLAuthCodeKeyboard string
AuthRequestExtraParams map[string]string
Username string
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",
"authcode-keyboard",
"password",
"device-code",
}, "|")
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")
f.StringVar(&o.LocalServerCertFile, "local-server-cert", "", "[authcode] Certificate path for the local server")
f.StringVar(&o.LocalServerKeyFile, "local-server-key", "", "[authcode] Certificate key path for the local server")
f.StringVar(&o.OpenURLAfterAuthentication, "open-url-after-authentication", "", "[authcode] If set, open the URL in the browser after authentication")
f.StringVar(&o.RedirectURLHostname, "oidc-redirect-url-hostname", "localhost", "[authcode] Hostname of the redirect URL")
f.StringVar(&o.RedirectURLAuthCodeKeyboard, "oidc-redirect-url-authcode-keyboard", oobRedirectURI, "[authcode-keyboard] Redirect URL")
f.StringToStringVar(&o.AuthRequestExtraParams, "oidc-auth-request-extra-params", nil, "[authcode, authcode-keyboard] Extra query parameters to send with an authentication request")
f.StringVar(&o.Username, "username", "", "[password] Username for resource owner password credentials grant")
f.StringVar(&o.Password, "password", "", "[password] Password for resource owner password credentials grant")
}
func (o *authenticationOptions) expandHomedir() {
o.LocalServerCertFile = expandHomedir(o.LocalServerCertFile)
o.LocalServerKeyFile = expandHomedir(o.LocalServerKeyFile)
}
func (o *authenticationOptions) grantOptionSet() (s authentication.GrantOptionSet, err error) {
switch {
case o.GrantType == "authcode" || (o.GrantType == "auto" && o.Username == ""):
s.AuthCodeBrowserOption = &authcode.BrowserOption{
BindAddress: o.determineListenAddress(),
SkipOpenBrowser: o.SkipOpenBrowser,
BrowserCommand: o.BrowserCommand,
AuthenticationTimeout: time.Duration(o.AuthenticationTimeoutSec) * time.Second,
LocalServerCertFile: o.LocalServerCertFile,
LocalServerKeyFile: o.LocalServerKeyFile,
OpenURLAfterAuthentication: o.OpenURLAfterAuthentication,
RedirectURLHostname: o.RedirectURLHostname,
AuthRequestExtraParams: o.AuthRequestExtraParams,
}
case o.GrantType == "authcode-keyboard":
s.AuthCodeKeyboardOption = &authcode.KeyboardOption{
AuthRequestExtraParams: o.AuthRequestExtraParams,
RedirectURL: o.RedirectURLAuthCodeKeyboard,
}
case o.GrantType == "password" || (o.GrantType == "auto" && o.Username != ""):
s.ROPCOption = &ropc.Option{
Username: o.Username,
Password: o.Password,
}
case o.GrantType == "device-code":
s.DeviceCodeOption = &devicecode.Option{
SkipOpenBrowser: o.SkipOpenBrowser,
BrowserCommand: o.BrowserCommand,
}
default:
err = fmt.Errorf("grant-type must be one of (%s)", allGrantType)
}
return
}

View File

@@ -0,0 +1,156 @@
package cmd
import (
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/int128/kubelogin/pkg/usecases/authentication"
"github.com/int128/kubelogin/pkg/usecases/authentication/authcode"
"github.com/int128/kubelogin/pkg/usecases/authentication/ropc"
"github.com/spf13/pflag"
)
func Test_authenticationOptions_grantOptionSet(t *testing.T) {
tests := map[string]struct {
args []string
want authentication.GrantOptionSet
}{
"NoFlag": {
want: authentication.GrantOptionSet{
AuthCodeBrowserOption: &authcode.BrowserOption{
BindAddress: defaultListenAddress,
AuthenticationTimeout: defaultAuthenticationTimeoutSec * time.Second,
RedirectURLHostname: "localhost",
},
},
},
"FullOptions": {
args: []string{
"--grant-type", "authcode",
"--listen-address", "127.0.0.1:10080",
"--listen-address", "127.0.0.1:20080",
"--skip-open-browser",
"--browser-command", "firefox",
"--authentication-timeout-sec", "10",
"--local-server-cert", "/path/to/local-server-cert",
"--local-server-key", "/path/to/local-server-key",
"--open-url-after-authentication", "https://example.com/success.html",
"--oidc-redirect-url-hostname", "example",
"--oidc-auth-request-extra-params", "ttl=86400",
"--oidc-auth-request-extra-params", "reauth=true",
"--username", "USER",
"--password", "PASS",
},
want: authentication.GrantOptionSet{
AuthCodeBrowserOption: &authcode.BrowserOption{
BindAddress: []string{"127.0.0.1:10080", "127.0.0.1:20080"},
SkipOpenBrowser: true,
BrowserCommand: "firefox",
AuthenticationTimeout: 10 * time.Second,
LocalServerCertFile: "/path/to/local-server-cert",
LocalServerKeyFile: "/path/to/local-server-key",
OpenURLAfterAuthentication: "https://example.com/success.html",
RedirectURLHostname: "example",
AuthRequestExtraParams: map[string]string{"ttl": "86400", "reauth": "true"},
},
},
},
"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",
},
want: authentication.GrantOptionSet{
AuthCodeKeyboardOption: &authcode.KeyboardOption{
RedirectURL: oobRedirectURI,
},
},
},
"GrantType=authcode-keyboard with full options": {
args: []string{
"--grant-type", "authcode-keyboard",
"--oidc-redirect-url-authcode-keyboard", "http://localhost",
},
want: authentication.GrantOptionSet{
AuthCodeKeyboardOption: &authcode.KeyboardOption{
RedirectURL: "http://localhost",
},
},
},
"GrantType=password": {
args: []string{
"--grant-type", "password",
"--listen-address", "127.0.0.1:10080",
"--listen-address", "127.0.0.1:20080",
"--username", "USER",
"--password", "PASS",
},
want: authentication.GrantOptionSet{
ROPCOption: &ropc.Option{
Username: "USER",
Password: "PASS",
},
},
},
"GrantType=auto": {
args: []string{
"--listen-address", "127.0.0.1:10080",
"--listen-address", "127.0.0.1:20080",
"--username", "USER",
"--password", "PASS",
},
want: authentication.GrantOptionSet{
ROPCOption: &ropc.Option{
Username: "USER",
Password: "PASS",
},
},
},
}
for name, c := range tests {
t.Run(name, func(t *testing.T) {
var o authenticationOptions
f := pflag.NewFlagSet("", pflag.ContinueOnError)
o.addFlags(f)
if err := f.Parse(c.args); err != nil {
t.Fatalf("Parse error: %s", err)
}
got, err := o.grantOptionSet()
if err != nil {
t.Fatalf("grantOptionSet error: %s", err)
}
if diff := cmp.Diff(c.want, got); diff != "" {
t.Errorf("mismatch (-want +got):\n%s", diff)
}
})
}
}

View File

@@ -2,13 +2,13 @@ package cmd
import (
"context"
"fmt"
"os"
"path/filepath"
"runtime"
"github.com/google/wire"
"github.com/int128/kubelogin/pkg/adaptors/logger"
"github.com/int128/kubelogin/pkg/infrastructure/logger"
"github.com/spf13/cobra"
"k8s.io/client-go/util/homedir"
)
// Set provides an implementation and interface for Cmd.
@@ -24,16 +24,20 @@ type Interface interface {
Run(ctx context.Context, args []string, version string) int
}
var defaultListenPort = []int{8000, 18000}
var defaultTokenCacheDir = homedir.HomeDir() + "/.kube/cache/oidc-login"
func translateListenPortToBindAddress(ports []int) (address []string) {
for _, p := range ports {
address = append(address, fmt.Sprintf("127.0.0.1:%d", p))
func getDefaultTokenCacheDir(key, fallback string) string {
if value, ok := os.LookupEnv(key); ok {
return value
}
return
return fallback
}
var defaultListenAddress = []string{"127.0.0.1:8000", "127.0.0.1:18000"}
var defaultTokenCacheDir = filepath.Join(
getDefaultTokenCacheDir("KUBECACHEDIR", filepath.Join("~", ".kube", "cache")),
"oidc-login")
const defaultAuthenticationTimeoutSec = 180
// Cmd provides interaction with command line interface (CLI).
type Cmd struct {
Root *Root
@@ -45,17 +49,15 @@ type Cmd struct {
// Run parses the command line arguments and executes the specified use-case.
// It returns an exit code, that is 0 on success or 1 on error.
func (cmd *Cmd) Run(ctx context.Context, args []string, version string) int {
executable := filepath.Base(args[0])
rootCmd := cmd.Root.New(ctx, executable)
rootCmd := cmd.Root.New()
rootCmd.Version = version
rootCmd.SilenceUsage = true
rootCmd.SilenceErrors = true
getTokenCmd := cmd.GetToken.New(ctx)
getTokenCmd := cmd.GetToken.New()
rootCmd.AddCommand(getTokenCmd)
setupCmd := cmd.Setup.New(ctx)
setupCmd := cmd.Setup.New()
rootCmd.AddCommand(setupCmd)
versionCmd := &cobra.Command{
@@ -63,13 +65,13 @@ func (cmd *Cmd) Run(ctx context.Context, args []string, version string) int {
Short: "Print the version information",
Args: cobra.NoArgs,
Run: func(*cobra.Command, []string) {
cmd.Logger.Printf("%s version %s", executable, version)
cmd.Logger.Printf("kubelogin version %s (%s %s_%s)", version, runtime.Version(), runtime.GOOS, runtime.GOARCH)
},
}
rootCmd.AddCommand(versionCmd)
rootCmd.SetArgs(args[1:])
if err := rootCmd.Execute(); err != nil {
if err := rootCmd.ExecuteContext(ctx); err != nil {
cmd.Logger.Printf("error: %s", err)
cmd.Logger.V(1).Infof("stacktrace: %+v", err)
return 1

246
pkg/cmd/cmd_test.go Normal file
View File

@@ -0,0 +1,246 @@
package cmd
import (
"context"
"os"
"path/filepath"
"testing"
"time"
"github.com/int128/kubelogin/pkg/oidc"
"github.com/int128/kubelogin/pkg/testing/logger"
"github.com/int128/kubelogin/pkg/tlsclientconfig"
"github.com/int128/kubelogin/pkg/usecases/authentication"
"github.com/int128/kubelogin/pkg/usecases/authentication/authcode"
"github.com/int128/kubelogin/pkg/usecases/credentialplugin"
"github.com/int128/kubelogin/pkg/usecases/standalone"
)
func TestCmd_Run(t *testing.T) {
const executable = "kubelogin"
const version = "HEAD"
t.Run("root", func(t *testing.T) {
tests := map[string]struct {
args []string
in standalone.Input
}{
"Defaults": {
args: []string{executable},
in: standalone.Input{
GrantOptionSet: authentication.GrantOptionSet{
AuthCodeBrowserOption: &authcode.BrowserOption{
BindAddress: defaultListenAddress,
AuthenticationTimeout: defaultAuthenticationTimeoutSec * time.Second,
RedirectURLHostname: "localhost",
},
},
},
},
"FullOptions": {
args: []string{executable,
"--kubeconfig", "/path/to/kubeconfig",
"--context", "hello.k8s.local",
"--user", "google",
"-v1",
},
in: standalone.Input{
KubeconfigFilename: "/path/to/kubeconfig",
KubeconfigContext: "hello.k8s.local",
KubeconfigUser: "google",
GrantOptionSet: authentication.GrantOptionSet{
AuthCodeBrowserOption: &authcode.BrowserOption{
BindAddress: defaultListenAddress,
AuthenticationTimeout: defaultAuthenticationTimeoutSec * time.Second,
RedirectURLHostname: "localhost",
},
},
},
},
}
for name, c := range tests {
t.Run(name, func(t *testing.T) {
ctx := context.TODO()
mockStandalone := standalone.NewMockInterface(t)
mockStandalone.EXPECT().
Do(ctx, c.in).
Return(nil)
cmd := Cmd{
Root: &Root{
Standalone: mockStandalone,
Logger: logger.New(t),
},
Logger: logger.New(t),
}
exitCode := cmd.Run(ctx, c.args, version)
if exitCode != 0 {
t.Errorf("exitCode wants 0 but %d", exitCode)
}
})
}
t.Run("TooManyArgs", func(t *testing.T) {
cmd := Cmd{
Root: &Root{
Standalone: standalone.NewMockInterface(t),
Logger: logger.New(t),
},
Logger: logger.New(t),
}
exitCode := cmd.Run(context.TODO(), []string{executable, "some"}, version)
if exitCode != 1 {
t.Errorf("exitCode wants 1 but %d", exitCode)
}
})
})
t.Run("get-token", func(t *testing.T) {
userHomeDir, err := os.UserHomeDir()
if err != nil {
t.Fatalf("os.UserHomeDir error: %s", err)
}
tests := map[string]struct {
args []string
in credentialplugin.Input
}{
"Defaults": {
args: []string{executable,
"get-token",
"--oidc-issuer-url", "https://issuer.example.com",
"--oidc-client-id", "YOUR_CLIENT_ID",
},
in: credentialplugin.Input{
TokenCacheDir: filepath.Join(userHomeDir, ".kube/cache/oidc-login"),
Provider: oidc.Provider{
IssuerURL: "https://issuer.example.com",
ClientID: "YOUR_CLIENT_ID",
},
GrantOptionSet: authentication.GrantOptionSet{
AuthCodeBrowserOption: &authcode.BrowserOption{
BindAddress: defaultListenAddress,
AuthenticationTimeout: defaultAuthenticationTimeoutSec * time.Second,
RedirectURLHostname: "localhost",
},
},
},
},
"FullOptions": {
args: []string{executable,
"get-token",
"--oidc-issuer-url", "https://issuer.example.com",
"--oidc-client-id", "YOUR_CLIENT_ID",
"--oidc-client-secret", "YOUR_CLIENT_SECRET",
"--oidc-extra-scope", "email",
"--oidc-extra-scope", "profile",
"-v1",
},
in: credentialplugin.Input{
TokenCacheDir: filepath.Join(userHomeDir, ".kube/cache/oidc-login"),
Provider: oidc.Provider{
IssuerURL: "https://issuer.example.com",
ClientID: "YOUR_CLIENT_ID",
ClientSecret: "YOUR_CLIENT_SECRET",
ExtraScopes: []string{"email", "profile"},
},
GrantOptionSet: authentication.GrantOptionSet{
AuthCodeBrowserOption: &authcode.BrowserOption{
BindAddress: defaultListenAddress,
AuthenticationTimeout: defaultAuthenticationTimeoutSec * time.Second,
RedirectURLHostname: "localhost",
},
},
},
},
"HomedirExpansion": {
args: []string{executable,
"get-token",
"--oidc-issuer-url", "https://issuer.example.com",
"--oidc-client-id", "YOUR_CLIENT_ID",
"--certificate-authority", "~/.kube/ca.crt",
"--local-server-cert", "~/.kube/oidc-server.crt",
"--local-server-key", "~/.kube/oidc-server.key",
"--token-cache-dir", "~/.kube/oidc-cache",
},
in: credentialplugin.Input{
TokenCacheDir: filepath.Join(userHomeDir, ".kube/oidc-cache"),
Provider: oidc.Provider{
IssuerURL: "https://issuer.example.com",
ClientID: "YOUR_CLIENT_ID",
},
GrantOptionSet: authentication.GrantOptionSet{
AuthCodeBrowserOption: &authcode.BrowserOption{
BindAddress: defaultListenAddress,
AuthenticationTimeout: defaultAuthenticationTimeoutSec * time.Second,
RedirectURLHostname: "localhost",
LocalServerCertFile: filepath.Join(userHomeDir, ".kube/oidc-server.crt"),
LocalServerKeyFile: filepath.Join(userHomeDir, ".kube/oidc-server.key"),
},
},
TLSClientConfig: tlsclientconfig.Config{
CACertFilename: []string{filepath.Join(userHomeDir, ".kube/ca.crt")},
},
},
},
}
for name, c := range tests {
t.Run(name, func(t *testing.T) {
ctx := context.TODO()
getToken := credentialplugin.NewMockInterface(t)
getToken.EXPECT().
Do(ctx, c.in).
Return(nil)
cmd := Cmd{
Root: &Root{
Logger: logger.New(t),
},
GetToken: &GetToken{
GetToken: getToken,
Logger: logger.New(t),
},
Logger: logger.New(t),
}
exitCode := cmd.Run(ctx, c.args, version)
if exitCode != 0 {
t.Errorf("exitCode wants 0 but %d", exitCode)
}
})
}
t.Run("MissingMandatoryOptions", func(t *testing.T) {
ctx := context.TODO()
cmd := Cmd{
Root: &Root{
Logger: logger.New(t),
},
GetToken: &GetToken{
GetToken: credentialplugin.NewMockInterface(t),
Logger: logger.New(t),
},
Logger: logger.New(t),
}
exitCode := cmd.Run(ctx, []string{executable, "get-token"}, version)
if exitCode != 1 {
t.Errorf("exitCode wants 1 but %d", exitCode)
}
})
t.Run("TooManyArgs", func(t *testing.T) {
ctx := context.TODO()
cmd := Cmd{
Root: &Root{
Logger: logger.New(t),
},
GetToken: &GetToken{
GetToken: credentialplugin.NewMockInterface(t),
Logger: logger.New(t),
},
Logger: logger.New(t),
}
exitCode := cmd.Run(ctx, []string{executable, "get-token", "foo"}, version)
if exitCode != 1 {
t.Errorf("exitCode wants 1 but %d", exitCode)
}
})
})
}

98
pkg/cmd/get_token.go Normal file
View File

@@ -0,0 +1,98 @@
package cmd
import (
"errors"
"fmt"
"github.com/int128/kubelogin/pkg/infrastructure/logger"
"github.com/int128/kubelogin/pkg/oidc"
"github.com/int128/kubelogin/pkg/usecases/credentialplugin"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
// getTokenOptions represents the options for get-token command.
type getTokenOptions struct {
IssuerURL string
ClientID string
ClientSecret string
ExtraScopes []string
UsePKCE bool
TokenCacheDir string
tlsOptions tlsOptions
authenticationOptions authenticationOptions
ForceRefresh bool
}
func (o *getTokenOptions) addFlags(f *pflag.FlagSet) {
f.StringVar(&o.IssuerURL, "oidc-issuer-url", "", "Issuer URL of the provider (mandatory)")
f.StringVar(&o.ClientID, "oidc-client-id", "", "Client ID of the provider (mandatory)")
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.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)
o.authenticationOptions.addFlags(f)
}
func (o *getTokenOptions) expandHomedir() error {
o.TokenCacheDir = expandHomedir(o.TokenCacheDir)
o.authenticationOptions.expandHomedir()
o.tlsOptions.expandHomedir()
return nil
}
type GetToken struct {
GetToken credentialplugin.Interface
Logger logger.Interface
}
func (cmd *GetToken) New() *cobra.Command {
var o getTokenOptions
c := &cobra.Command{
Use: "get-token [flags]",
Short: "Run as a kubectl credential plugin",
Args: func(c *cobra.Command, args []string) error {
if err := cobra.NoArgs(c, args); err != nil {
return err
}
if o.IssuerURL == "" {
return errors.New("--oidc-issuer-url is missing")
}
if o.ClientID == "" {
return errors.New("--oidc-client-id is missing")
}
return nil
},
RunE: func(c *cobra.Command, _ []string) error {
if err := o.expandHomedir(); err != nil {
return err
}
grantOptionSet, err := o.authenticationOptions.grantOptionSet()
if err != nil {
return fmt.Errorf("get-token: %w", err)
}
in := credentialplugin.Input{
Provider: oidc.Provider{
IssuerURL: o.IssuerURL,
ClientID: o.ClientID,
ClientSecret: o.ClientSecret,
UsePKCE: o.UsePKCE,
ExtraScopes: o.ExtraScopes,
},
TokenCacheDir: o.TokenCacheDir,
GrantOptionSet: grantOptionSet,
TLSClientConfig: o.tlsOptions.tlsClientConfig(),
ForceRefresh: o.ForceRefresh,
}
if err := cmd.GetToken.Do(c.Context(), in); err != nil {
return fmt.Errorf("get-token: %w", err)
}
return nil
},
}
c.Flags().SortFlags = false
o.addFlags(c.Flags())
return c
}

15
pkg/cmd/homedir.go Normal file
View File

@@ -0,0 +1,15 @@
package cmd
import (
"path/filepath"
"strings"
"k8s.io/client-go/util/homedir"
)
func expandHomedir(s string) string {
if !strings.HasPrefix(s, "~") {
return s
}
return filepath.Join(homedir.HomeDir(), strings.TrimPrefix(s, "~"))
}

76
pkg/cmd/mock_Interface.go Normal file
View File

@@ -0,0 +1,76 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
package cmd
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}
}
// Run provides a mock function with given fields: ctx, args, version
func (_m *MockInterface) Run(ctx context.Context, args []string, version string) int {
ret := _m.Called(ctx, args, version)
var r0 int
if rf, ok := ret.Get(0).(func(context.Context, []string, string) int); ok {
r0 = rf(ctx, args, version)
} else {
r0 = ret.Get(0).(int)
}
return r0
}
// MockInterface_Run_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Run'
type MockInterface_Run_Call struct {
*mock.Call
}
// Run is a helper method to define mock.On call
// - ctx context.Context
// - args []string
// - version string
func (_e *MockInterface_Expecter) Run(ctx interface{}, args interface{}, version interface{}) *MockInterface_Run_Call {
return &MockInterface_Run_Call{Call: _e.mock.On("Run", ctx, args, version)}
}
func (_c *MockInterface_Run_Call) Run(run func(ctx context.Context, args []string, version string)) *MockInterface_Run_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(context.Context), args[1].([]string), args[2].(string))
})
return _c
}
func (_c *MockInterface_Run_Call) Return(_a0 int) *MockInterface_Run_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
}

74
pkg/cmd/root.go Normal file
View File

@@ -0,0 +1,74 @@
package cmd
import (
"fmt"
"github.com/int128/kubelogin/pkg/infrastructure/logger"
"github.com/int128/kubelogin/pkg/kubeconfig"
"github.com/int128/kubelogin/pkg/usecases/standalone"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
const rootDescription = `Log in to the OpenID Connect provider.
You need to set up the OIDC provider, role binding, Kubernetes API server and kubeconfig.
To show the setup instruction:
kubectl oidc-login setup
See https://github.com/int128/kubelogin for more.
`
// rootOptions represents the options for the root command.
type rootOptions struct {
Kubeconfig string
Context string
User string
tlsOptions tlsOptions
authenticationOptions authenticationOptions
}
func (o *rootOptions) addFlags(f *pflag.FlagSet) {
f.StringVar(&o.Kubeconfig, "kubeconfig", "", "Path to the kubeconfig file")
f.StringVar(&o.Context, "context", "", "Name of the kubeconfig context to use")
f.StringVar(&o.User, "user", "", "Name of the kubeconfig user to use. Prior to --context")
o.tlsOptions.addFlags(f)
o.authenticationOptions.addFlags(f)
}
type Root struct {
Standalone standalone.Interface
Logger logger.Interface
}
func (cmd *Root) New() *cobra.Command {
var o rootOptions
c := &cobra.Command{
Use: "kubelogin",
Short: "Log in to the OpenID Connect provider",
Long: rootDescription,
Args: cobra.NoArgs,
RunE: func(c *cobra.Command, _ []string) error {
grantOptionSet, err := o.authenticationOptions.grantOptionSet()
if err != nil {
return fmt.Errorf("invalid option: %w", err)
}
in := standalone.Input{
KubeconfigFilename: o.Kubeconfig,
KubeconfigContext: kubeconfig.ContextName(o.Context),
KubeconfigUser: kubeconfig.UserName(o.User),
GrantOptionSet: grantOptionSet,
TLSClientConfig: o.tlsOptions.tlsClientConfig(),
}
if err := cmd.Standalone.Do(c.Context(), in); err != nil {
return fmt.Errorf("login: %w", err)
}
return nil
},
}
c.Flags().SortFlags = false
o.addFlags(c.Flags())
cmd.Logger.AddFlags(c.PersistentFlags())
return c
}

View File

@@ -1,12 +1,11 @@
package cmd
import (
"context"
"fmt"
"github.com/int128/kubelogin/pkg/usecases/setup"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"golang.org/x/xerrors"
)
// setupOptions represents the options for setup command.
@@ -15,27 +14,26 @@ type setupOptions struct {
ClientID string
ClientSecret string
ExtraScopes []string
CertificateAuthority string
SkipTLSVerify bool
UsePKCE bool
tlsOptions tlsOptions
authenticationOptions authenticationOptions
}
func (o *setupOptions) register(f *pflag.FlagSet) {
f.SortFlags = false
func (o *setupOptions) addFlags(f *pflag.FlagSet) {
f.StringVar(&o.IssuerURL, "oidc-issuer-url", "", "Issuer URL of the provider")
f.StringVar(&o.ClientID, "oidc-client-id", "", "Client ID of the provider")
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.StringVar(&o.CertificateAuthority, "certificate-authority", "", "Path to a cert file for the certificate authority")
f.BoolVar(&o.SkipTLSVerify, "insecure-skip-tls-verify", false, "If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure")
o.authenticationOptions.register(f)
f.BoolVar(&o.UsePKCE, "oidc-use-pkce", false, "Force PKCE usage")
o.tlsOptions.addFlags(f)
o.authenticationOptions.addFlags(f)
}
type Setup struct {
Setup setup.Interface
}
func (cmd *Setup) New(ctx context.Context) *cobra.Command {
func (cmd *Setup) New() *cobra.Command {
var o setupOptions
c := &cobra.Command{
Use: "setup",
@@ -44,30 +42,31 @@ func (cmd *Setup) New(ctx context.Context) *cobra.Command {
RunE: func(c *cobra.Command, _ []string) error {
grantOptionSet, err := o.authenticationOptions.grantOptionSet()
if err != nil {
return xerrors.Errorf("error: %w", err)
return fmt.Errorf("setup: %w", err)
}
in := setup.Stage2Input{
IssuerURL: o.IssuerURL,
ClientID: o.ClientID,
ClientSecret: o.ClientSecret,
ExtraScopes: o.ExtraScopes,
CACertFilename: o.CertificateAuthority,
SkipTLSVerify: o.SkipTLSVerify,
GrantOptionSet: grantOptionSet,
IssuerURL: o.IssuerURL,
ClientID: o.ClientID,
ClientSecret: o.ClientSecret,
ExtraScopes: o.ExtraScopes,
UsePKCE: o.UsePKCE,
GrantOptionSet: grantOptionSet,
TLSClientConfig: o.tlsOptions.tlsClientConfig(),
}
if c.Flags().Lookup("listen-port").Changed {
in.ListenPortArgs = o.authenticationOptions.ListenPort
if c.Flags().Lookup("listen-address").Changed {
in.ListenAddressArgs = o.authenticationOptions.ListenAddress
}
if in.IssuerURL == "" || in.ClientID == "" {
cmd.Setup.DoStage1()
return nil
}
if err := cmd.Setup.DoStage2(ctx, in); err != nil {
return xerrors.Errorf("error: %w", err)
if err := cmd.Setup.DoStage2(c.Context(), in); err != nil {
return fmt.Errorf("setup: %w", err)
}
return nil
},
}
o.register(c.Flags())
c.Flags().SortFlags = false
o.addFlags(c.Flags())
return c
}

52
pkg/cmd/tls.go Normal file
View File

@@ -0,0 +1,52 @@
package cmd
import (
"crypto/tls"
"github.com/int128/kubelogin/pkg/tlsclientconfig"
"github.com/spf13/pflag"
)
type tlsOptions struct {
CACertFilename []string
CACertData []string
SkipTLSVerify bool
RenegotiateOnceAsClient bool
RenegotiateFreelyAsClient bool
}
func (o *tlsOptions) addFlags(f *pflag.FlagSet) {
f.StringArrayVar(&o.CACertFilename, "certificate-authority", nil, "Path to a cert file for the certificate authority")
f.StringArrayVar(&o.CACertData, "certificate-authority-data", nil, "Base64 encoded cert for the certificate authority")
f.BoolVar(&o.SkipTLSVerify, "insecure-skip-tls-verify", false, "If set, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure")
f.BoolVar(&o.RenegotiateOnceAsClient, "tls-renegotiation-once", false, "If set, allow a remote server to request renegotiation once per connection")
f.BoolVar(&o.RenegotiateFreelyAsClient, "tls-renegotiation-freely", false, "If set, allow a remote server to repeatedly request renegotiation")
}
func (o *tlsOptions) expandHomedir() {
var caCertFilenames []string
for _, caCertFilename := range o.CACertFilename {
expanded := expandHomedir(caCertFilename)
caCertFilenames = append(caCertFilenames, expanded)
}
o.CACertFilename = caCertFilenames
}
func (o tlsOptions) tlsClientConfig() tlsclientconfig.Config {
return tlsclientconfig.Config{
CACertFilename: o.CACertFilename,
CACertData: o.CACertData,
SkipTLSVerify: o.SkipTLSVerify,
Renegotiation: o.renegotiationSupport(),
}
}
func (o tlsOptions) renegotiationSupport() tls.RenegotiationSupport {
if o.RenegotiateOnceAsClient {
return tls.RenegotiateOnceAsClient
}
if o.RenegotiateFreelyAsClient {
return tls.RenegotiateFreelyAsClient
}
return tls.RenegotiateNever
}

92
pkg/cmd/tls_test.go Normal file
View File

@@ -0,0 +1,92 @@
package cmd
import (
"crypto/tls"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/int128/kubelogin/pkg/tlsclientconfig"
"github.com/spf13/pflag"
)
func Test_tlsOptions_tlsClientConfig(t *testing.T) {
tests := map[string]struct {
args []string
want tlsclientconfig.Config
}{
"NoFlag": {},
"SkipTLSVerify": {
args: []string{
"--insecure-skip-tls-verify",
},
want: tlsclientconfig.Config{
SkipTLSVerify: true,
},
},
"CACertFilename1": {
args: []string{
"--certificate-authority", "/path/to/cert1",
},
want: tlsclientconfig.Config{
CACertFilename: []string{"/path/to/cert1"},
},
},
"CACertFilename2": {
args: []string{
"--certificate-authority", "/path/to/cert1",
"--certificate-authority", "/path/to/cert2",
},
want: tlsclientconfig.Config{
CACertFilename: []string{"/path/to/cert1", "/path/to/cert2"},
},
},
"CACertData1": {
args: []string{
"--certificate-authority-data", "base64encoded1",
},
want: tlsclientconfig.Config{
CACertData: []string{"base64encoded1"},
},
},
"CACertData2": {
args: []string{
"--certificate-authority-data", "base64encoded1",
"--certificate-authority-data", "base64encoded2",
},
want: tlsclientconfig.Config{
CACertData: []string{"base64encoded1", "base64encoded2"},
},
},
"RenegotiateOnceAsClient": {
args: []string{
"--tls-renegotiation-once",
},
want: tlsclientconfig.Config{
Renegotiation: tls.RenegotiateOnceAsClient,
},
},
"RenegotiateFreelyAsClient": {
args: []string{
"--tls-renegotiation-freely",
},
want: tlsclientconfig.Config{
Renegotiation: tls.RenegotiateFreelyAsClient,
},
},
}
for name, c := range tests {
t.Run(name, func(t *testing.T) {
var o tlsOptions
f := pflag.NewFlagSet("", pflag.ContinueOnError)
o.addFlags(f)
if err := f.Parse(c.args); err != nil {
t.Fatalf("Parse error: %s", err)
}
got := o.tlsClientConfig()
if diff := cmp.Diff(c.want, got); diff != "" {
t.Errorf("mismatch (-want +got):\n%s", diff)
}
})
}
}

View File

@@ -0,0 +1,10 @@
// Package credentialplugin provides the types for client-go credential plugins.
package credentialplugin
import "time"
// Output represents an output object of the credential plugin.
type Output struct {
Token string
Expiry time.Time
}

View File

@@ -0,0 +1,45 @@
// Package writer provides a writer for a credential plugin.
package writer
import (
"encoding/json"
"fmt"
"github.com/google/wire"
"github.com/int128/kubelogin/pkg/credentialplugin"
"github.com/int128/kubelogin/pkg/infrastructure/stdio"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
)
var Set = wire.NewSet(
wire.Struct(new(Writer), "*"),
wire.Bind(new(Interface), new(*Writer)),
)
type Interface interface {
Write(out credentialplugin.Output) error
}
type Writer struct {
Stdout stdio.Stdout
}
// 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},
},
}
e := json.NewEncoder(w.Stdout)
if err := e.Encode(ec); err != nil {
return fmt.Errorf("could not write the ExecCredential: %w", err)
}
return nil
}

View File

@@ -0,0 +1,73 @@
// Code generated by mockery v2.13.1. DO NOT EDIT.
package writer
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}
}
// Write provides a mock function with given fields: out
func (_m *MockInterface) Write(out credentialplugin.Output) error {
ret := _m.Called(out)
var r0 error
if rf, ok := ret.Get(0).(func(credentialplugin.Output) error); ok {
r0 = rf(out)
} else {
r0 = ret.Error(0)
}
return r0
}
// MockInterface_Write_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Write'
type MockInterface_Write_Call struct {
*mock.Call
}
// Write is a helper method to define mock.On call
// - out credentialplugin.Output
func (_e *MockInterface_Expecter) Write(out interface{}) *MockInterface_Write_Call {
return &MockInterface_Write_Call{Call: _e.mock.On("Write", out)}
}
func (_c *MockInterface_Write_Call) Run(run func(out credentialplugin.Output)) *MockInterface_Write_Call {
_c.Call.Run(func(args mock.Arguments) {
run(args[0].(credentialplugin.Output))
})
return _c
}
func (_c *MockInterface_Write_Call) Return(_a0 error) *MockInterface_Write_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,64 +1,63 @@
//+build wireinject
//go:build wireinject
// +build wireinject
// Package di provides dependency injection.
package di
import (
"github.com/google/wire"
"github.com/int128/kubelogin/pkg/adaptors/certpool"
"github.com/int128/kubelogin/pkg/adaptors/cmd"
credentialPluginAdaptor "github.com/int128/kubelogin/pkg/adaptors/credentialplugin"
"github.com/int128/kubelogin/pkg/adaptors/env"
"github.com/int128/kubelogin/pkg/adaptors/jwtdecoder"
"github.com/int128/kubelogin/pkg/adaptors/kubeconfig"
"github.com/int128/kubelogin/pkg/adaptors/logger"
"github.com/int128/kubelogin/pkg/adaptors/oidcclient"
"github.com/int128/kubelogin/pkg/adaptors/tokencache"
"github.com/int128/kubelogin/pkg/cmd"
"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"
kubeconfigWriter "github.com/int128/kubelogin/pkg/kubeconfig/writer"
"github.com/int128/kubelogin/pkg/oidc/client"
"github.com/int128/kubelogin/pkg/tlsclientconfig/loader"
"github.com/int128/kubelogin/pkg/tokencache/repository"
"github.com/int128/kubelogin/pkg/usecases/authentication"
credentialPluginUseCase "github.com/int128/kubelogin/pkg/usecases/credentialplugin"
"github.com/int128/kubelogin/pkg/usecases/credentialplugin"
"github.com/int128/kubelogin/pkg/usecases/setup"
"github.com/int128/kubelogin/pkg/usecases/standalone"
)
// NewCmd returns an instance of adaptors.Cmd.
// NewCmd returns an instance of infrastructure.Cmd.
func NewCmd() cmd.Interface {
wire.Build(
NewCmdForHeadless,
// dependencies for production
clock.Set,
stdio.Set,
logger.Set,
browser.Set,
)
return nil
}
// NewCmdForHeadless returns an instance of infrastructure.Cmd for headless testing.
func NewCmdForHeadless(clock.Interface, stdio.Stdin, stdio.Stdout, logger.Interface, browser.Interface) cmd.Interface {
wire.Build(
// use-cases
authentication.Set,
wire.Value(authentication.DefaultLocalServerReadyFunc),
standalone.Set,
credentialPluginUseCase.Set,
credentialplugin.Set,
setup.Set,
// adaptors
// infrastructure
cmd.Set,
env.Set,
kubeconfig.Set,
tokencache.Set,
credentialPluginAdaptor.Set,
oidcclient.Set,
jwtdecoder.Set,
certpool.Set,
logger.Set,
)
return nil
}
// NewCmdForHeadless returns an instance of adaptors.Cmd for headless testing.
func NewCmdForHeadless(logger.Interface, authentication.LocalServerReadyFunc, credentialPluginAdaptor.Interface) cmd.Interface {
wire.Build(
authentication.Set,
standalone.Set,
credentialPluginUseCase.Set,
setup.Set,
cmd.Set,
env.Set,
kubeconfig.Set,
tokencache.Set,
oidcclient.Set,
jwtdecoder.Set,
certpool.Set,
reader.Set,
kubeconfigLoader.Set,
kubeconfigWriter.Set,
repository.Set,
client.Set,
loader.Set,
writer.Set,
mutex.Set,
)
return nil
}

View File

@@ -1,152 +1,113 @@
// Code generated by Wire. DO NOT EDIT.
//go:generate wire
//+build !wireinject
//go:generate go run github.com/google/wire/cmd/wire
//go:build !wireinject
// +build !wireinject
package di
import (
"github.com/int128/kubelogin/pkg/adaptors/certpool"
"github.com/int128/kubelogin/pkg/adaptors/cmd"
"github.com/int128/kubelogin/pkg/adaptors/credentialplugin"
"github.com/int128/kubelogin/pkg/adaptors/env"
"github.com/int128/kubelogin/pkg/adaptors/jwtdecoder"
"github.com/int128/kubelogin/pkg/adaptors/kubeconfig"
"github.com/int128/kubelogin/pkg/adaptors/logger"
"github.com/int128/kubelogin/pkg/adaptors/oidcclient"
"github.com/int128/kubelogin/pkg/adaptors/tokencache"
"github.com/int128/kubelogin/pkg/cmd"
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"
"github.com/int128/kubelogin/pkg/kubeconfig/writer"
"github.com/int128/kubelogin/pkg/oidc/client"
"github.com/int128/kubelogin/pkg/tlsclientconfig/loader"
"github.com/int128/kubelogin/pkg/tokencache/repository"
"github.com/int128/kubelogin/pkg/usecases/authentication"
credentialplugin2 "github.com/int128/kubelogin/pkg/usecases/credentialplugin"
"github.com/int128/kubelogin/pkg/usecases/authentication/authcode"
"github.com/int128/kubelogin/pkg/usecases/authentication/devicecode"
"github.com/int128/kubelogin/pkg/usecases/authentication/ropc"
"github.com/int128/kubelogin/pkg/usecases/credentialplugin"
"github.com/int128/kubelogin/pkg/usecases/setup"
"github.com/int128/kubelogin/pkg/usecases/standalone"
"os"
)
// Injectors from di.go:
// NewCmd returns an instance of infrastructure.Cmd.
func NewCmd() cmd.Interface {
clockReal := &clock.Real{}
stdin := _wireFileValue
stdout := _wireOsFileValue
loggerInterface := logger.New()
factory := &oidcclient.Factory{
Logger: loggerInterface,
}
decoder := &jwtdecoder.Decoder{}
envEnv := &env.Env{}
localServerReadyFunc := _wireLocalServerReadyFuncValue
authCode := &authentication.AuthCode{
Env: envEnv,
Logger: loggerInterface,
LocalServerReadyFunc: localServerReadyFunc,
}
authCodeKeyboard := &authentication.AuthCodeKeyboard{
Env: envEnv,
Logger: loggerInterface,
}
ropc := &authentication.ROPC{
Env: envEnv,
Logger: loggerInterface,
}
authenticationAuthentication := &authentication.Authentication{
OIDCClientFactory: factory,
JWTDecoder: decoder,
Logger: loggerInterface,
AuthCode: authCode,
AuthCodeKeyboard: authCodeKeyboard,
ROPC: ropc,
}
kubeconfigKubeconfig := &kubeconfig.Kubeconfig{
Logger: loggerInterface,
}
certpoolFactory := &certpool.Factory{}
standaloneStandalone := &standalone.Standalone{
Authentication: authenticationAuthentication,
Kubeconfig: kubeconfigKubeconfig,
CertPoolFactory: certpoolFactory,
Logger: loggerInterface,
}
root := &cmd.Root{
Standalone: standaloneStandalone,
Logger: loggerInterface,
}
repository := &tokencache.Repository{}
interaction := &credentialplugin.Interaction{}
getToken := &credentialplugin2.GetToken{
Authentication: authenticationAuthentication,
TokenCacheRepository: repository,
CertPoolFactory: certpoolFactory,
Interaction: interaction,
Logger: loggerInterface,
}
cmdGetToken := &cmd.GetToken{
GetToken: getToken,
Logger: loggerInterface,
}
setupSetup := &setup.Setup{
Authentication: authenticationAuthentication,
CertPoolFactory: certpoolFactory,
Logger: loggerInterface,
}
cmdSetup := &cmd.Setup{
Setup: setupSetup,
}
cmdCmd := &cmd.Cmd{
Root: root,
GetToken: cmdGetToken,
Setup: cmdSetup,
Logger: loggerInterface,
}
return cmdCmd
browserBrowser := &browser.Browser{}
cmdInterface := NewCmdForHeadless(clockReal, stdin, stdout, loggerInterface, browserBrowser)
return cmdInterface
}
var (
_wireLocalServerReadyFuncValue = authentication.DefaultLocalServerReadyFunc
_wireFileValue = os.Stdin
_wireOsFileValue = os.Stdout
)
func NewCmdForHeadless(loggerInterface logger.Interface, localServerReadyFunc authentication.LocalServerReadyFunc, credentialpluginInterface credentialplugin.Interface) cmd.Interface {
factory := &oidcclient.Factory{
// NewCmdForHeadless returns an instance of infrastructure.Cmd for headless testing.
func NewCmdForHeadless(clockInterface clock.Interface, stdin stdio.Stdin, stdout stdio.Stdout, loggerInterface logger.Interface, browserInterface browser.Interface) cmd.Interface {
loaderLoader := loader.Loader{}
factory := &client.Factory{
Loader: loaderLoader,
Clock: clockInterface,
Logger: loggerInterface,
}
decoder := &jwtdecoder.Decoder{}
envEnv := &env.Env{}
authCode := &authentication.AuthCode{
Env: envEnv,
Logger: loggerInterface,
LocalServerReadyFunc: localServerReadyFunc,
authcodeBrowser := &authcode.Browser{
Browser: browserInterface,
Logger: loggerInterface,
}
authCodeKeyboard := &authentication.AuthCodeKeyboard{
Env: envEnv,
readerReader := &reader.Reader{
Stdin: stdin,
}
keyboard := &authcode.Keyboard{
Reader: readerReader,
Logger: loggerInterface,
}
ropc := &authentication.ROPC{
Env: envEnv,
ropcROPC := &ropc.ROPC{
Reader: readerReader,
Logger: loggerInterface,
}
deviceCode := &devicecode.DeviceCode{
Browser: browserInterface,
Logger: loggerInterface,
}
authenticationAuthentication := &authentication.Authentication{
OIDCClientFactory: factory,
JWTDecoder: decoder,
Logger: loggerInterface,
AuthCode: authCode,
AuthCodeKeyboard: authCodeKeyboard,
ROPC: ropc,
ClientFactory: factory,
Logger: loggerInterface,
Clock: clockInterface,
AuthCodeBrowser: authcodeBrowser,
AuthCodeKeyboard: keyboard,
ROPC: ropcROPC,
DeviceCode: deviceCode,
}
kubeconfigKubeconfig := &kubeconfig.Kubeconfig{
Logger: loggerInterface,
}
certpoolFactory := &certpool.Factory{}
loader3 := &loader2.Loader{}
writerWriter := &writer.Writer{}
standaloneStandalone := &standalone.Standalone{
Authentication: authenticationAuthentication,
Kubeconfig: kubeconfigKubeconfig,
CertPoolFactory: certpoolFactory,
Logger: loggerInterface,
Authentication: authenticationAuthentication,
KubeconfigLoader: loader3,
KubeconfigWriter: writerWriter,
Logger: loggerInterface,
}
root := &cmd.Root{
Standalone: standaloneStandalone,
Logger: loggerInterface,
}
repository := &tokencache.Repository{}
getToken := &credentialplugin2.GetToken{
repositoryRepository := &repository.Repository{}
writer3 := &writer2.Writer{
Stdout: stdout,
}
mutexMutex := &mutex.Mutex{
Logger: loggerInterface,
}
getToken := &credentialplugin.GetToken{
Authentication: authenticationAuthentication,
TokenCacheRepository: repository,
CertPoolFactory: certpoolFactory,
Interaction: credentialpluginInterface,
TokenCacheRepository: repositoryRepository,
Writer: writer3,
Mutex: mutexMutex,
Logger: loggerInterface,
}
cmdGetToken := &cmd.GetToken{
@@ -154,9 +115,8 @@ func NewCmdForHeadless(loggerInterface logger.Interface, localServerReadyFunc au
Logger: loggerInterface,
}
setupSetup := &setup.Setup{
Authentication: authenticationAuthentication,
CertPoolFactory: certpoolFactory,
Logger: loggerInterface,
Authentication: authenticationAuthentication,
Logger: loggerInterface,
}
cmdSetup := &cmd.Setup{
Setup: setupSetup,

View File

@@ -1,65 +0,0 @@
package oidc
import (
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"encoding/binary"
"strings"
"golang.org/x/xerrors"
)
func NewState() (string, error) {
b, err := random32()
if err != nil {
return "", xerrors.Errorf("could not generate a random: %w", err)
}
return base64URLEncode(b), nil
}
func NewNonce() (string, error) {
b, err := random32()
if err != nil {
return "", xerrors.Errorf("could not generate a random: %w", err)
}
return base64URLEncode(b), nil
}
type PKCEParams struct {
CodeChallenge string
CodeChallengeMethod string
CodeVerifier string
}
func NewPKCEParams() (*PKCEParams, error) {
b, err := random32()
if err != nil {
return nil, xerrors.Errorf("could not generate a random: %w", err)
}
s := computeS256(b)
return &s, nil
}
func random32() ([]byte, error) {
b := make([]byte, 32)
if err := binary.Read(rand.Reader, binary.LittleEndian, b); err != nil {
return nil, xerrors.Errorf("could not read: %w", err)
}
return b, nil
}
func computeS256(b []byte) PKCEParams {
v := base64URLEncode(b)
s := sha256.New()
_, _ = s.Write([]byte(v))
return PKCEParams{
CodeChallenge: base64URLEncode(s.Sum(nil)),
CodeChallengeMethod: "S256",
CodeVerifier: v,
}
}
func base64URLEncode(b []byte) string {
return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=")
}

View File

@@ -1,25 +0,0 @@
package oidc
import (
"testing"
)
func Test_computeS256(t *testing.T) {
// Testdata described at:
// https://tools.ietf.org/html/rfc7636#appendix-B
b := []byte{
116, 24, 223, 180, 151, 153, 224, 37, 79, 250, 96, 125, 216, 173,
187, 186, 22, 212, 37, 77, 105, 214, 191, 240, 91, 88, 5, 88, 83,
132, 141, 121,
}
p := computeS256(b)
if want := "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"; want != p.CodeVerifier {
t.Errorf("CodeVerifier wants %s but was %s", want, p.CodeVerifier)
}
if want := "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"; want != p.CodeChallenge {
t.Errorf("CodeChallenge wants %s but was %s", want, p.CodeChallenge)
}
if p.CodeChallengeMethod != "S256" {
t.Errorf("CodeChallengeMethod wants S256 but was %s", p.CodeChallengeMethod)
}
}

Some files were not shown because too many files have changed in this diff Show More