diff --git a/README.md b/README.md index e9bafcc..20f2b8c 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,8 @@ By default the tool creates the session name - which can be audited including th ## [Usage](./docs/usage.md) +### [Using Custom Debug Browser](./docs/using-custom-debug-browser.md) + ## Known Issues - Even though a datadir is created to store the chromium session data it is advised to still open settings and save the username/password manually the first time you are presented with the login screen. @@ -51,7 +53,7 @@ By default the tool creates the session name - which can be audited including th ## Contribute -Contributions to the aws-auth-cli package are most welcome from engineers of all backgrounds and skill levels. +Contributions to the aws-auth-cli package are most welcome from engineers of all backgrounds and skill levels. In particular the addition of extra test coverage, code enhacements. @@ -68,5 +70,5 @@ To make a contribution: Inspired by/Borrowed the design for secretStore from these 2 packages: -- [Hiroyuki Wada](https://github.com/wadahiro) [package](https://github.com/openstandia/aws-cli-oidc) +- [Hiroyuki Wada](https://github.com/wadahiro) [package](https://github.com/openstandia/aws-cli-oidc) - [Mark Wolfe](https://github.com/wolfeidau) [package](https://github.com/Versent/saml2aws) diff --git a/cmd/saml.go b/cmd/saml.go index ce4c48f..96b1a21 100755 --- a/cmd/saml.go +++ b/cmd/saml.go @@ -167,11 +167,11 @@ You should find it in the IAM portal e.g.: arn:aws:iam::1234567891012:saml-provi sc.cmd.PersistentFlags().StringVarP(&flags.SsoRegion, "sso-region", "", "eu-west-1", "If using SSO, you must set the region") sc.cmd.PersistentFlags().StringVarP(&flags.CustomExecutablePath, "executable-path", "", "", `Custom path to an executable -This needs to be a chromium like executable - e.g. Chrome, Chromium, Brave, Edge. +This needs to be a chromium like executable - e.g. Chrome, Chromium, Brave, Edge. You can find out the path by opening your browser and typing in chrome|brave|edge://version `) - sc.cmd.PersistentFlags().BoolVarP(&flags.IsSso, "is-sso", "", false, `Enables the new AWS User portal login. + sc.cmd.PersistentFlags().BoolVarP(&flags.IsSso, "is-sso", "", false, `Enables the new AWS User portal login. If this flag is specified the --sso-role must also be specified.`) sc.cmd.PersistentFlags().IntVarP(&flags.ReloadBeforeTime, "reload-before", "", 0, "Triggers a credentials refresh before the specified max-duration. Value provided in seconds. Should be less than the max-duration of the session") // @@ -189,12 +189,17 @@ func samlInitConfig(customPath string) (*ini.File, error) { configPath := credentialexchange.ConfigIniFile(customPath) if _, err := os.Stat(configPath); err != nil { // creating a file - rolesInit := []byte(fmt.Sprintf("; aws-cli-auth generated [role] section\n[%s]\n", credentialexchange.INI_CONF_SECTION)) + rolesInit := []byte(fmt.Sprintf("; aws-cli-auth generated [role] section\n[%s]\n", credentialexchange.INI_ROLE_SECTION)) if err := os.WriteFile(configPath, rolesInit, 0644); err != nil { return nil, err } } - return ini.Load(configPath) + cfg, err := ini.Load(configPath) + if err != nil { + return nil, err + } + credentialexchange.EnsureParentSections(cfg) + return cfg, nil } func ConfigFromFlags(fileConfig *credentialexchange.CredentialConfig, rf *RootCmdFlags, sf *SamlCmdFlags, user string) error { diff --git a/docs/using-custom-debug-browser.md b/docs/using-custom-debug-browser.md new file mode 100644 index 0000000..d34f077 --- /dev/null +++ b/docs/using-custom-debug-browser.md @@ -0,0 +1,44 @@ +# Using Custom Debug Browser + +It might be desirable to run your own debug browser for running the tests in +environments such as WSL which might have no browser installed. + +`aws-cli-auth` will look for an environment variable named `ROD_BROWSER_WS_URL` +and will use this Web Socket URL as the browser to use for communications. + +## Example (MSEdge) + +For example, to run a debug browser using MSEdge: +```bash +msedge \ + --remote-debugging-port=9222 \ + --user-data-dir='C:\temp\test' +``` + +> NOTE: The `--user-data-dir` parameter isn't strictly necessary, but if MSEdge +> is open for whatever reason then it'll re-use that window and you won't get a +> debug instance. Sometimes Windows suspends a closed window and this results in +> it thinking the window is still open. + +### WSL Usage + +When exposing debug browsers like MSEdge the `--remote-debugging-address` is +ignored. This means it binds to 127.0.0.1 explicitly which WSL (by default) +can't. + +To mitiagte this please add to your `~/.wslconfig`: +```ini +[wsl2] +networkingMode=mirrored +``` + +This will allow WSL to access ports bound to 127.0.0.1 on the Windows host as if +they were bound through WSL. + +### VSCode Tests + +By adding a `ROD_BROWSER_WS_URL` to the `./vscode/settings.json` the tests can +then use the debug browser added above. E.g.: +```json +"ROD_BROWSER_WS_URL": "ws://127.0.0.1:9222/devtools/browser/b28bdd90-8c1d-478b-8294-1e3fd3170f4d", +``` diff --git a/eirctl.yaml b/eirctl.yaml index 9b69aad..e6dda0b 100644 --- a/eirctl.yaml +++ b/eirctl.yaml @@ -1,14 +1,14 @@ import: - - https://raw.githubusercontent.com/Ensono/eirctl/refs/tags/v0.9.7/shared/build/go/eirctl.yaml + - https://raw.githubusercontent.com/Ensono/eirctl/refs/tags/v0.10.0/shared/build/go/eirctl.yaml contexts: bash: container: - name: mirror.gcr.io/bash:5.0.18-alpine3.22 + name: mirror.gcr.io/bash:5.3.9-alpine3.23 unit:test: container: - name: ghcr.io/devlabfoundry/aws-cli-auth-ci:0.3.0 + name: ghcr.io/devlabfoundry/aws-cli-auth-ci:0.17.2 entrypoint: /usr/bin/env envfile: exclude: @@ -72,9 +72,9 @@ tasks: - | mkdir -p .coverage export GOPATH="${PWD}/.deps" GOBIN="${PWD}/.deps/bin" - go install github.com/jstemmer/go-junit-report@v0.9.1 - go install github.com/axw/gocov/gocov@v1.0.0 - go install github.com/AlekSi/gocov-xml@v1.0.0 + go install github.com/jstemmer/go-junit-report@v1.0.0 + go install github.com/axw/gocov/gocov@v1.2.1 + go install github.com/AlekSi/gocov-xml@v1.2.0 clean:dir: command: @@ -160,4 +160,4 @@ tasks: echo "Coverage file first 20 lines after conversion:" head -20 .coverage/out echo "Coverage file line count:" - wc -l .coverage/out \ No newline at end of file + wc -l .coverage/out diff --git a/go.mod b/go.mod index 7303595..753d2cc 100644 --- a/go.mod +++ b/go.mod @@ -1,61 +1,63 @@ module github.com/DevLabFoundry/aws-cli-auth -go 1.25 +go 1.26 -toolchain go1.25.7 +toolchain go1.26.2 require ( - github.com/aws/aws-sdk-go-v2 v1.39.6 - github.com/aws/aws-sdk-go-v2/config v1.31.20 - github.com/aws/aws-sdk-go-v2/service/sts v1.40.2 - github.com/aws/smithy-go v1.23.2 + github.com/aws/aws-sdk-go-v2 v1.41.6 + github.com/aws/aws-sdk-go-v2/config v1.32.16 + github.com/aws/aws-sdk-go-v2/service/sts v1.42.0 + github.com/aws/smithy-go v1.25.0 github.com/go-rod/rod v0.116.2 - github.com/rezakhademix/govalidator/v2 v2.1.2 + github.com/rezakhademix/govalidator/v2 v2.2.1 github.com/savioxavier/termlink v1.4.3 - github.com/spf13/cobra v1.10.1 + github.com/spf13/cobra v1.10.2 github.com/werf/lockgate v0.1.1 - github.com/zalando/go-keyring v0.2.6 - gopkg.in/ini.v1 v1.67.0 + github.com/zalando/go-keyring v0.2.8 + gopkg.in/ini.v1 v1.67.1 ) require ( + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.23 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.10 // indirect github.com/mattn/go-colorable v0.1.14 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-isatty v0.0.21 // indirect github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/schollz/progressbar/v3 v3.18.0 // indirect - golang.org/x/term v0.37.0 // indirect + github.com/schollz/progressbar/v3 v3.19.0 // indirect + golang.org/x/term v0.42.0 // indirect ) require ( al.essio.dev/pkg/shellescape v1.6.0 // indirect dario.cat/mergo v1.0.2 - github.com/Ensono/eirctl v0.9.6 - github.com/aws/aws-sdk-go-v2/credentials v1.18.24 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.13 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.30.3 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.7 // indirect + github.com/Ensono/eirctl v0.10.0 + github.com/aws/aws-sdk-go-v2/credentials v1.19.15 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.8 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.22 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.16 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20 // indirect github.com/danieljoos/wincred v1.2.3 // indirect github.com/go-test/deep v1.1.1 - github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/godbus/dbus/v5 v5.2.2 // indirect github.com/gofrs/flock v0.13.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/rs/zerolog v1.34.0 + github.com/rs/zerolog v1.35.1 github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/ysmood/fetchup v0.5.3 // indirect github.com/ysmood/goob v0.4.0 // indirect - github.com/ysmood/got v0.42.0 // indirect + github.com/ysmood/got v0.42.4 // indirect github.com/ysmood/gson v0.7.3 // indirect github.com/ysmood/leakless v0.9.0 // indirect - golang.org/x/crypto v0.44.0 // indirect - golang.org/x/sys v0.38.0 // indirect + golang.org/x/crypto v0.50.0 // indirect + golang.org/x/sys v0.43.0 // indirect ) replace github.com/ysmood/fetchup => github.com/ysmood/fetchup v0.3.0 diff --git a/go.sum b/go.sum index fc7250c..cdca689 100644 --- a/go.sum +++ b/go.sum @@ -4,50 +4,86 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= github.com/Ensono/eirctl v0.9.6 h1:G6S0ZJ2VtedGW2/nn8sbMQnNbLVXgjwNJnuLEHUjJRc= github.com/Ensono/eirctl v0.9.6/go.mod h1:pxX1iE+guf8Lyvs98FkNnMKqyTtHaLrJgB3f4foEROk= +github.com/Ensono/eirctl v0.10.0 h1:NwbJw0OgTcO8hcqdqE+JQUPz6URcUlXKd/Hn8RukKFk= +github.com/Ensono/eirctl v0.10.0/go.mod h1:ReuTkHwrX0zPIRYGHBfQqUCEX0TUKZvBlO3AN6oo7ZY= github.com/aws/aws-sdk-go-v2 v1.39.6 h1:2JrPCVgWJm7bm83BDwY5z8ietmeJUbh3O2ACnn+Xsqk= github.com/aws/aws-sdk-go-v2 v1.39.6/go.mod h1:c9pm7VwuW0UPxAEYGyTmyurVcNrbF6Rt/wixFqDhcjE= +github.com/aws/aws-sdk-go-v2 v1.41.6 h1:1AX0AthnBQzMx1vbmir3Y4WsnJgiydmnJjiLu+LvXOg= +github.com/aws/aws-sdk-go-v2 v1.41.6/go.mod h1:dy0UzBIfwSeot4grGvY1AqFWN5zgziMmWGzysDnHFcQ= github.com/aws/aws-sdk-go-v2/config v1.31.20 h1:/jWF4Wu90EhKCgjTdy1DGxcbcbNrjfBHvksEL79tfQc= github.com/aws/aws-sdk-go-v2/config v1.31.20/go.mod h1:95Hh1Tc5VYKL9NJ7tAkDcqeKt+MCXQB1hQZaRdJIZE0= +github.com/aws/aws-sdk-go-v2/config v1.32.16 h1:Q0iQ7quUgJP0F/SCRTieScnaMdXr9h/2+wze1u3cNeM= +github.com/aws/aws-sdk-go-v2/config v1.32.16/go.mod h1:duCCnJEFqpt2RC6no1iK6q+8HpwOAkiUua0pY507dQc= github.com/aws/aws-sdk-go-v2/credentials v1.18.24 h1:iJ2FmPT35EaIB0+kMa6TnQ+PwG5A1prEdAw+PsMzfHg= github.com/aws/aws-sdk-go-v2/credentials v1.18.24/go.mod h1:U91+DrfjAiXPDEGYhh/x29o4p0qHX5HDqG7y5VViv64= +github.com/aws/aws-sdk-go-v2/credentials v1.19.15 h1:fyvgWTszojq8hEnMi8PPBTvZdTtEVmAVyo+NFLHBhH4= +github.com/aws/aws-sdk-go-v2/credentials v1.19.15/go.mod h1:gJiYyMOjNg8OEdRWOf3CrFQxM2a98qmrtjx1zuiQfB8= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13 h1:T1brd5dR3/fzNFAQch/iBKeX07/ffu/cLu+q+RuzEWk= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.13/go.mod h1:Peg/GBAQ6JDt+RoBf4meB1wylmAipb7Kg2ZFakZTlwk= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.22 h1:IOGsJ1xVWhsi+ZO7/NW8OuZZBtMJLZbk4P5HDjJO0jQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.22/go.mod h1:b+hYdbU+jGKfXE8kKM6g1+h+L/Go3vMvzlxBsiuGsxg= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13 h1:a+8/MLcWlIxo1lF9xaGt3J/u3yOZx+CdSveSNwjhD40= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.13/go.mod h1:oGnKwIYZ4XttyU2JWxFrwvhF6YKiK/9/wmE3v3Iu9K8= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22 h1:GmLa5Kw1ESqtFpXsx5MmC84QWa/ZrLZvlJGa2y+4kcQ= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22/go.mod h1:6sW9iWm9DK9YRpRGga/qzrzNLgKpT2cIxb7Vo2eNOp0= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.13 h1:HBSI2kDkMdWz4ZM7FjwE7e/pWDEZ+nR95x8Ztet1ooY= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.13/go.mod h1:YE94ZoDArI7awZqJzBAZ3PDD2zSfuP7w6P2knOzIn8M= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22 h1:dY4kWZiSaXIzxnKlj17nHnBcXXBfac6UlsAx2qL6XrU= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22/go.mod h1:KIpEUx0JuRZLO7U6cbV204cWAEco2iC3l061IxlwLtI= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4 h1:WKuaxf++XKWlHWu9ECbMlha8WOEGm0OUEZqm4K/Gcfk= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.4/go.mod h1:ZWy7j6v1vWGmPReu0iSGvRiise4YI5SkR3OHKTZ6Wuc= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6 h1:qYQ4pzQ2Oz6WpQ8T3HvGHnZydA72MnLuFK9tJwmrbHw= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.6/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.23 h1:FPXsW9+gMuIeKmz7j6ENWcWtBGTe1kH8r9thNt5Uxx4= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.23/go.mod h1:7J8iGMdRKk6lw2C+cMIphgAnT8uTwBwNOsGkyOCm80U= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3 h1:x2Ibm/Af8Fi+BH+Hsn9TXGdT+hKbDd5XOTZxTMxDk7o= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.3/go.mod h1:IW1jwyrQgMdhisceG8fQLmQIydcT/jWY21rFhzgaKwo= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.8 h1:HtOTYcbVcGABLOVuPYaIihj6IlkqubBwFj10K5fxRek= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.8/go.mod h1:VsK9abqQeGlzPgUr+isNWzPlK2vKe9INMLWnY65f5Xs= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13 h1:kDqdFvMY4AtKoACfzIGD8A0+hbT41KTKF//gq7jITfM= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.13/go.mod h1:lmKuogqSU3HzQCwZ9ZtcqOc5XGMqtDK7OIc2+DxiUEg= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.22 h1:PUmZeJU6Y1Lbvt9WFuJ0ugUK2xn6hIWUBBbKuOWF30s= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.22/go.mod h1:nO6egFBoAaoXze24a2C0NjQCvdpk8OueRoYimvEB9jo= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.10 h1:a1Fq/KXn75wSzoJaPQTgZO0wHGqE9mjFnylnqEPTchA= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.10/go.mod h1:p6+MXNxW7IA6dMgHfTAzljuwSKD0NCm/4lbS4t6+7vI= github.com/aws/aws-sdk-go-v2/service/sso v1.30.3 h1:NjShtS1t8r5LUfFVtFeI8xLAHQNTa7UI0VawXlrBMFQ= github.com/aws/aws-sdk-go-v2/service/sso v1.30.3/go.mod h1:fKvyjJcz63iL/ftA6RaM8sRCtN4r4zl4tjL3qw5ec7k= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.16 h1:x6bKbmDhsgSZwv6q19wY/u3rLk/3FGjJWyqKcIRufpE= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.16/go.mod h1:CudnEVKRtLn0+3uMV0yEXZ+YZOKnAtUJ5DmDhilVnIw= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.7 h1:gTsnx0xXNQ6SBbymoDvcoRHL+q4l/dAFsQuKfDWSaGc= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.7/go.mod h1:klO+ejMvYsB4QATfEOIXk8WAEwN4N0aBfJpvC+5SZBo= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20 h1:oK/njaL8GtyEihkWMD4k3VgHCT64RQKkZwh0DG5j8ak= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20/go.mod h1:JHs8/y1f3zY7U5WcuzoJ/yAYGYtNIVPKLIbp61euvmg= github.com/aws/aws-sdk-go-v2/service/sts v1.40.2 h1:HK5ON3KmQV2HcAunnx4sKLB9aPf3gKGwVAf7xnx0QT0= github.com/aws/aws-sdk-go-v2/service/sts v1.40.2/go.mod h1:E19xDjpzPZC7LS2knI9E6BaRFDK43Eul7vd6rSq2HWk= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.0 h1:ks8KBcZPh3PYISr5dAiXCM5/Thcuxk8l+PG4+A0exds= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.0/go.mod h1:pFw33T0WLvXU3rw1WBkpMlkgIn54eCB5FYLhjDc9Foo= github.com/aws/smithy-go v1.23.2 h1:Crv0eatJUQhaManss33hS5r40CG3ZFH+21XSkqMrIUM= github.com/aws/smithy-go v1.23.2/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= +github.com/aws/smithy-go v1.25.0 h1:Sz/XJ64rwuiKtB6j98nDIPyYrV1nVNJ4YU74gttcl5U= +github.com/aws/smithy-go v1.25.0/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg= github.com/briandowns/spinner v1.23.2 h1:Zc6ecUnI+YzLmJniCfDNaMbW0Wid1d5+qcTq4L2FW8w= github.com/briandowns/spinner v1.23.2/go.mod h1:LaZeM4wm2Ywy6vO571mvhQNRcWfRUnXOs0RcKV0wYKM= github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= +github.com/buger/jsonparser v1.1.2 h1:frqHqw7otoVbk5M8LlE/L7HTnIq2v9RX6EJ48i9AxJk= github.com/chengxilo/virtualterm v1.0.4 h1:Z6IpERbRVlfB8WkOmtbHiDbBANU7cimRIof7mk9/PwM= github.com/chengxilo/virtualterm v1.0.4/go.mod h1:DyxxBZz/x1iqJjFxTFcr6/x+jSpqN0iwWCOK1q10rlY= github.com/clipperhouse/uax29/v2 v2.2.0 h1:ChwIKnQN3kcZteTXMgb1wztSgaU+ZemkgWdohwgs8tY= github.com/clipperhouse/uax29/v2 v2.2.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= +github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/danieljoos/wincred v1.2.3 h1:v7dZC2x32Ut3nEfRH+vhoZGvN72+dQ/snVXo/vMFLdQ= github.com/danieljoos/wincred v1.2.3/go.mod h1:6qqX0WNrS4RzPZ1tnroDzq9kY3fu1KwE7MRLQK4X0bs= +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/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= +github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= github.com/go-rod/rod v0.116.2 h1:A5t2Ky2A+5eD/ZJQr1EfsQSe5rms5Xof/qj296e+ZqA= github.com/go-rod/rod v0.116.2/go.mod h1:H+CMO9SCNc2TJ2WfrG+pKhITz57uGNYU43qYHh438Mg= github.com/go-test/deep v1.1.1 h1:0r/53hagsehfO4bzD2Pgr/+RgHqhmf+k1Bpse2cTu1U= @@ -55,6 +91,8 @@ github.com/go-test/deep v1.1.1/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncV github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.2.2 h1:TUR3TgtSVDmjiXOgAAyaZbYmIeP3DPkld3jgKGV8mXQ= +github.com/godbus/dbus/v5 v5.2.2/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c= github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw= github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= @@ -67,6 +105,7 @@ github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcI github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= github.com/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8= github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= +github.com/mailru/easyjson v0.9.2 h1:dX8U45hQsZpxd80nLvDGihsQ/OxlvTkVUXH2r/8cb2M= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= @@ -74,8 +113,11 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.21 h1:xYae+lCNBP7QuW4PUnNG61ffM4hVIfm+zUzDuSzYLGs= +github.com/mattn/go-isatty v0.0.21/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4= github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= +github.com/mattn/go-runewidth v0.0.23 h1:7ykA0T0jkPpzSvMS5i9uoNn2Xy3R383f9HDx3RybWcw= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -83,27 +125,42 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rezakhademix/govalidator/v2 v2.1.2 h1:qqCIkWC6sWr8zeW9zCkYEJxbZMt/Dn1ASXkGIQe3rDI= github.com/rezakhademix/govalidator/v2 v2.1.2/go.mod h1:be7JrYM3STiL5jYt1WrQN5ArR8xTov/DvWJ9yXtULj8= +github.com/rezakhademix/govalidator/v2 v2.2.1 h1:1eEZsj0shiSIx51k7shGm9P6C82EKcaKpqt+YsI0NDU= +github.com/rezakhademix/govalidator/v2 v2.2.1/go.mod h1:be7JrYM3STiL5jYt1WrQN5ArR8xTov/DvWJ9yXtULj8= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= +github.com/rs/zerolog v1.35.1 h1:m7xQeoiLIiV0BCEY4Hs+j2NG4Gp2o2KPKmhnnLiazKI= +github.com/rs/zerolog v1.35.1/go.mod h1:EjML9kdfa/RMA7h/6z6pYmq1ykOuA8/mjWaEvGI+jcw= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/savioxavier/termlink v1.4.3 h1:Gh6vrG7jSn21cRiYdQqFXYcdXfM+Fg14aG487JTfKpA= github.com/savioxavier/termlink v1.4.3/go.mod h1:5T5ePUlWbxCHIwyF8/Ez1qufOoGM89RCg9NvG+3G3gc= github.com/schollz/progressbar/v3 v3.18.0 h1:uXdoHABRFmNIjUfte/Ex7WtuyVslrw2wVPQmCN62HpA= github.com/schollz/progressbar/v3 v3.18.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec= +github.com/schollz/progressbar/v3 v3.19.0 h1:Ea18xuIRQXLAUidVDox3AbwfUhD0/1IvohyTutOIFoc= +github.com/schollz/progressbar/v3 v3.19.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= +github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 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.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/werf/lockgate v0.1.1 h1:S400JFYjtWfE4i4LY9FA8zx0fMdfui9DPrBiTciCrx4= @@ -116,8 +173,11 @@ github.com/ysmood/goob v0.4.0 h1:HsxXhyLBeGzWXnqVKtmT9qM7EuVs/XOgkX7T6r1o1AQ= github.com/ysmood/goob v0.4.0/go.mod h1:u6yx7ZhS4Exf2MwciFr6nIM8knHQIE22lFpWHnfql18= github.com/ysmood/gop v0.3.0 h1:b/t6tbGSIaSqfnhb1R6Xkye4ZkINfKiUxYZF33JEZWU= github.com/ysmood/gop v0.3.0/go.mod h1:K4LAB/BdLArknXrVSy+DyXcfb8P85JwAtwYM8zlb0mU= +github.com/ysmood/gop v0.3.2 h1:8JKMweQJcWPeVj89YkQaAdbjGGPZ0TiBtYXLYyjMVWw= github.com/ysmood/got v0.42.0 h1:CMRoknemO2nkZBpZmRgsWs79UoQz5eDfWmKIAGGFm94= github.com/ysmood/got v0.42.0/go.mod h1:uFF8sPWgVvWIGrjASUgtH0AbnU7ipaXGVaFtWdl3yP0= +github.com/ysmood/got v0.42.4 h1:D6HKIuoGprHb/D2kkYYVZc9MehD7XQQKG6uKUrVfxaI= +github.com/ysmood/got v0.42.4/go.mod h1:nQvPHRFpbmt8UghB9qpjwIpKbJaMro1s8rc37M/Sqg8= github.com/ysmood/gotrace v0.6.0 h1:SyI1d4jclswLhg7SWTL6os3L1WOKeNn/ZtzVQF8QmdY= github.com/ysmood/gotrace v0.6.0/go.mod h1:TzhIG7nHDry5//eYZDYcTzuJLYQIkykJzCRIo4/dzQM= github.com/ysmood/gson v0.7.3 h1:QFkWbTH8MxyUTKPkVWAENJhxqdBa4lYTQWqZCiLG6kE= @@ -126,17 +186,29 @@ github.com/ysmood/leakless v0.9.0 h1:qxCG5VirSBvmi3uynXFkcnLMzkphdh3xx5FtrORwDCU github.com/ysmood/leakless v0.9.0/go.mod h1:R8iAXPRaG97QJwqxs74RdwzcRHT1SWCGTNqY8q0JvMQ= github.com/zalando/go-keyring v0.2.6 h1:r7Yc3+H+Ux0+M72zacZoItR3UDxeWfKTcabvkI8ua9s= github.com/zalando/go-keyring v0.2.6/go.mod h1:2TCrxYrbUNYfNS/Kgy/LSrkSQzZ5UPVH85RwfczwvcI= +github.com/zalando/go-keyring v0.2.8 h1:6sD/Ucpl7jNq10rM2pgqTs0sZ9V3qMrqfIIy5YPccHs= +github.com/zalando/go-keyring v0.2.8/go.mod h1:tsMo+VpRq5NGyKfxoBVjCuMrG47yj8cmakZDO5QGii0= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU= golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc= +golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= +golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= +golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY= +golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/ini.v1 v1.67.1 h1:tVBILHy0R6e4wkYOn3XmiITt/hEVH4TFMYvAX2Ytz6k= +gopkg.in/ini.v1 v1.67.1/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/credentialexchange/config.go b/internal/credentialexchange/config.go index 93bcb55..251afa4 100644 --- a/internal/credentialexchange/config.go +++ b/internal/credentialexchange/config.go @@ -7,10 +7,11 @@ import ( ) const ( - SELF_NAME = "aws-cli-auth" - WEB_ID_TOKEN_VAR = "AWS_WEB_IDENTITY_TOKEN_FILE" - AWS_ROLE_ARN = "AWS_ROLE_ARN" - INI_CONF_SECTION = "role" + SELF_NAME = "aws-cli-auth" + WEB_ID_TOKEN_VAR = "AWS_WEB_IDENTITY_TOKEN_FILE" + AWS_ROLE_ARN = "AWS_ROLE_ARN" + INI_ROLE_SECTION = "role" + INI_CONFIG_SECTION = "config" ) type BaseConfig struct { diff --git a/internal/credentialexchange/credentialexchange_test.go b/internal/credentialexchange/credentialexchange_test.go index 038fdd3..4b619dd 100644 --- a/internal/credentialexchange/credentialexchange_test.go +++ b/internal/credentialexchange/credentialexchange_test.go @@ -282,7 +282,7 @@ func Test_IsValid_with(t *testing.T) { func Test_LoginAwsWebToken_with(t *testing.T) { ttests := map[string]struct { srv func(t *testing.T) *credentialexchange.CredentialExchange - setup func() func() + setup func(t *testing.T) func() currCred *credentialexchange.AWSCredentials expectErr bool errTyp error @@ -298,16 +298,13 @@ func Test_LoginAwsWebToken_with(t *testing.T) { } return credentialexchange.New(zerolog.Nop().With().Logger(), a) }, - setup: func() func() { - tmpDir, _ := os.MkdirTemp(os.TempDir(), "web-id") + setup: func(t *testing.T) func() { + tmpDir := t.TempDir() tokenFile := path.Join(tmpDir, ".ignore-token") _ = os.WriteFile(tokenFile, []byte(`sometoikonsebjsxd`), 0777) - _ = os.Setenv(credentialexchange.WEB_ID_TOKEN_VAR, tokenFile) - _ = os.Setenv("AWS_ROLE_ARN", "somerole") - return func() { - os.Clearenv() - _ = os.RemoveAll(tmpDir) - } + t.Setenv(credentialexchange.WEB_ID_TOKEN_VAR, tokenFile) + t.Setenv("AWS_ROLE_ARN", "somerole") + return func() {} }, currCred: mockSuccessCreds, expectErr: false, @@ -321,16 +318,13 @@ func Test_LoginAwsWebToken_with(t *testing.T) { } return credentialexchange.New(zerolog.Nop().With().Logger(), a) }, - setup: func() func() { - tmpDir, _ := os.MkdirTemp(os.TempDir(), "web-id") + setup: func(t *testing.T) func() { + tmpDir := t.TempDir() tokenFile := path.Join(tmpDir, ".ignore-token") _ = os.WriteFile(tokenFile, []byte(`sometoikonsebjsxd`), 0777) - _ = os.Setenv(credentialexchange.WEB_ID_TOKEN_VAR, tokenFile) - _ = os.Setenv("AWS_ROLE_ARN", "somerole") - return func() { - os.Clearenv() - _ = os.RemoveAll(tmpDir) - } + t.Setenv(credentialexchange.WEB_ID_TOKEN_VAR, tokenFile) + t.Setenv("AWS_ROLE_ARN", "somerole") + return func() {} }, currCred: mockSuccessCreds, expectErr: true, @@ -347,7 +341,7 @@ func Test_LoginAwsWebToken_with(t *testing.T) { } return credentialexchange.New(zerolog.Nop().With().Logger(), a) }, - setup: func() func() { + setup: func(t *testing.T) func() { return func() {} }, currCred: mockSuccessCreds, @@ -366,16 +360,9 @@ func Test_LoginAwsWebToken_with(t *testing.T) { return credentialexchange.New(zerolog.Nop().With().Logger(), a) }, - setup: func() func() { - // tmpDir, _ := os.MkdirTemp(os.TempDir(), "web-id") - // tokenFile := path.Join(tmpDir, ".ignore-token") - // os.WriteFile(tokenFile, []byte(`sometoikonsebjsxd`), 0777) - // os.Setenv(credentialexchange.WEB_ID_TOKEN_VAR, tokenFile) - _ = os.Setenv("AWS_ROLE_ARN", "somerole") - return func() { - os.Clearenv() - // os.RemoveAll(tmpDir) - } + setup: func(t *testing.T) func() { + t.Setenv("AWS_ROLE_ARN", "somerole") + return func() {} }, currCred: mockSuccessCreds, expectErr: true, @@ -384,7 +371,7 @@ func Test_LoginAwsWebToken_with(t *testing.T) { } for name, tt := range ttests { t.Run(name, func(t *testing.T) { - tearDown := tt.setup() + tearDown := tt.setup(t) defer tearDown() got, err := tt.srv(t).LoginAwsWebToken(context.TODO(), "username") diff --git a/internal/credentialexchange/helper.go b/internal/credentialexchange/helper.go index 8a7a5c6..e8cb23e 100644 --- a/internal/credentialexchange/helper.go +++ b/internal/credentialexchange/helper.go @@ -97,9 +97,26 @@ func ReloadBeforeExpiry(expiry time.Time, reloadBeforeSeconds int) bool { return diff.Seconds() < float64(reloadBeforeSeconds) } +// EnsureParentSections guarantees that every dotted child section in the file +// (e.g. [config.foo] or [role.my-role]) has an explicit parent section. +// gopkg.in/ini.v1 does not auto-create parent sections, so HasSection("config") +// returns false when only [config.foo] is present, breaking child-section +// lookups. Calling this once after ini.Load normalises the file in memory +// without touching the file on disk. +func EnsureParentSections(cfg *ini.File) { + for _, s := range cfg.Sections() { + if idx := strings.LastIndex(s.Name(), "."); idx > 0 { + parent := s.Name()[:idx] + if !cfg.HasSection(parent) { + _, _ = cfg.NewSection(parent) + } + } + } +} + func LoadCliConfig(cfg *ini.File, cfgSection string) (*CredentialConfig, error) { - if cfg.HasSection("config") { - configSection, err := cfg.GetSection("config") + if cfg.HasSection(INI_CONFIG_SECTION) { + configSection, err := cfg.GetSection(INI_CONFIG_SECTION) if err != nil { return nil, err } @@ -108,7 +125,7 @@ func LoadCliConfig(cfg *ini.File, cfgSection string) (*CredentialConfig, error) _ = configSection.MapTo(mainConfig) _ = configSection.MapTo(mainBaseConfig) for _, section := range configSection.ChildSections() { - if fmt.Sprintf("config.%s", cfgSection) == section.Name() { + if fmt.Sprintf("%s.%s", INI_CONFIG_SECTION, cfgSection) == section.Name() { sectionBaseConfig := &BaseConfig{} sectionConfig := &CredentialConfig{} _ = section.MapTo(sectionConfig) @@ -126,7 +143,7 @@ func LoadCliConfig(cfg *ini.File, cfgSection string) (*CredentialConfig, error) // WriteIniSection update ini sections in own config file func WriteIniSection(role string) error { - section := fmt.Sprintf("%s.%s", INI_CONF_SECTION, RoleKeyConverter(role)) + section := fmt.Sprintf("%s.%s", INI_ROLE_SECTION, RoleKeyConverter(role)) cfg, err := ini.Load(ConfigIniFile("")) if err != nil { return fmt.Errorf("fail to read Ini file: %v, %w", err, ErrConfigFailure) diff --git a/internal/credentialexchange/helper_test.go b/internal/credentialexchange/helper_test.go index fcbf9cd..99537d9 100644 --- a/internal/credentialexchange/helper_test.go +++ b/internal/credentialexchange/helper_test.go @@ -4,7 +4,6 @@ import ( "fmt" "os" "path" - "strings" "testing" "time" @@ -33,8 +32,8 @@ func TestCreateEntryInIni(t *testing.T) { t.Fatalf("Fail to read file: %v", err) } - section := cfg.Section(credentialexchange.INI_CONF_SECTION) // - if !cfg.HasSection(fmt.Sprintf("%s.%s", credentialexchange.INI_CONF_SECTION, credentialexchange.RoleKeyConverter(roleTest))) { + section := cfg.Section(credentialexchange.INI_ROLE_SECTION) // + if !cfg.HasSection(fmt.Sprintf("%s.%s", credentialexchange.INI_ROLE_SECTION, credentialexchange.RoleKeyConverter(roleTest))) { t.Errorf("section NOT Exists") } roles := section.ChildSections() @@ -75,24 +74,19 @@ func TestReloadBeforeExpiryNeedToRefresh(t *testing.T) { func Test_HomeDirOverwritten(t *testing.T) { ttests := map[string]struct { - setUpCleanUp func() func() + setUpCleanUp func(t *testing.T) func() }{ "test1": { - setUpCleanUp: func() func() { - orignalEnv := os.Environ() - os.Setenv("HOME", "./.ignore-delete") - return func() { - for _, e := range orignalEnv { - pair := strings.SplitN(e, "=", 2) - _ = os.Setenv(pair[0], pair[1]) - } - } + setUpCleanUp: func(t *testing.T) func() { + t.Setenv("HOME", "./.ignore-delete") + t.Setenv("USERPROFILE", "./.ignore-delete") + return func() {} }, }, } for name, tt := range ttests { t.Run(name, func(t *testing.T) { - cleanUp := tt.setUpCleanUp() + cleanUp := tt.setUpCleanUp(t) defer cleanUp() got := credentialexchange.HomeDir() if got != "./.ignore-delete" { @@ -139,19 +133,17 @@ func Test_InsertIntoRoleSlice_with(t *testing.T) { func Test_SetCredentials_with(t *testing.T) { ttests := map[string]struct { - setup func() func() + setup func(t *testing.T) func() conf credentialexchange.CredentialConfig cred func() *credentialexchange.AWSCredentials expectErr bool }{ "write to creds file": { - setup: func() func() { - tempDir, _ := os.MkdirTemp(os.TempDir(), "set-creds-tester") - os.Setenv("HOME", tempDir) - return func() { - os.Clearenv() - _ = os.RemoveAll(tempDir) - } + setup: func(t *testing.T) func() { + tempDir := t.TempDir() + t.Setenv("HOME", tempDir) + t.Setenv("USERPROFILE", tempDir) + return func() {} }, cred: func() *credentialexchange.AWSCredentials { return mockSuccessCreds @@ -164,13 +156,11 @@ func Test_SetCredentials_with(t *testing.T) { }, }, "write to stdout": { - setup: func() func() { - tempDir, _ := os.MkdirTemp(os.TempDir(), "set-creds-tester") - os.Setenv("HOME", tempDir) - return func() { - os.Clearenv() - _ = os.RemoveAll(tempDir) - } + setup: func(t *testing.T) func() { + tempDir := t.TempDir() + t.Setenv("HOME", tempDir) + t.Setenv("USERPROFILE", tempDir) + return func() {} }, cred: func() *credentialexchange.AWSCredentials { return mockSuccessCreds @@ -183,15 +173,13 @@ func Test_SetCredentials_with(t *testing.T) { }, }, "write using AWS_CREDENTIALS_FILE": { - setup: func() func() { - tempDir, _ := os.MkdirTemp(os.TempDir(), "set-creds-tester") - _ = os.Setenv("HOME", tempDir) + setup: func(t *testing.T) func() { + tempDir := t.TempDir() + t.Setenv("HOME", tempDir) + t.Setenv("USERPROFILE", tempDir) _ = os.WriteFile(path.Join(tempDir, "creds"), []byte(``), 0777) - _ = os.Setenv("AWS_SHARED_CREDENTIALS_FILE", path.Join(tempDir, "creds")) - return func() { - os.Clearenv() - _ = os.RemoveAll(tempDir) - } + t.Setenv("AWS_SHARED_CREDENTIALS_FILE", path.Join(tempDir, "creds")) + return func() {} }, cred: func() *credentialexchange.AWSCredentials { return mockSuccessCreds @@ -233,7 +221,7 @@ func Test_SetCredentials_with(t *testing.T) { } for name, tt := range ttests { t.Run(name, func(t *testing.T) { - cleanUp := tt.setup() + cleanUp := tt.setup(t) defer cleanUp() @@ -289,3 +277,76 @@ provider-url = https://accounts.google.com/o/saml2/initsso?idpid=some-foo-id123& t.Error() } } + +// Test_Helper_LoadCliConfig_NoRootSection verifies that a config file containing +// only a named sub-section (e.g. [config.foo]) without a root [config] section +// is loaded correctly after EnsureParentSections normalises the file. +func Test_Helper_LoadCliConfig_NoRootSection(t *testing.T) { + f, err := os.CreateTemp(os.TempDir(), "ini-conf-norootsection-*") + if err != nil { + t.Fatal(err) + } + defer os.Remove(f.Name()) + f.Write([]byte(` +[config.specific_section] +role = arn:aws:iam::1233444555:role/SSO-admin +principal = arn:aws:iam::1233444555:saml-provider/GoogleIdP +provider-url = https://accounts.google.com/o/saml2/initsso?idpid=some-foo-id123&forceauthn=false +duration = 3600 +browser-executable-path = "/my/Browser" +`)) + iniFile, err := ini.Load(credentialexchange.ConfigIniFile(f.Name())) + if err != nil { + t.Fatal(err) + } + credentialexchange.EnsureParentSections(iniFile) + cfg, err := credentialexchange.LoadCliConfig(iniFile, "specific_section") + if err != nil { + t.Fatal(err) + } + if cfg.Duration != 3600 { + t.Errorf("expected duration 3600, got %d", cfg.Duration) + } + if cfg.BaseConfig.Role != "arn:aws:iam::1233444555:role/SSO-admin" { + t.Errorf("expected role arn, got %q", cfg.BaseConfig.Role) + } + if cfg.BaseConfig.BrowserExecutablePath != "/my/Browser" { + t.Errorf("expected browser path, got %q", cfg.BaseConfig.BrowserExecutablePath) + } + if cfg.ProviderUrl != "https://accounts.google.com/o/saml2/initsso?idpid=some-foo-id123&forceauthn=false" { + t.Errorf("expected provider-url, got %q", cfg.ProviderUrl) + } +} + +// Test_EnsureParentSections verifies that EnsureParentSections creates blank +// parent sections for all dotted child sections, covering both [config.*] and +// [role.*] shapes used in the config file. +func Test_EnsureParentSections(t *testing.T) { + content := []byte(` +[config.foo] +provider-url = https://example.com + +[role.arn_aws_iam__123456789_role__My-Role] +name = arn:aws:iam::123456789:role/My-Role +`) + iniFile, err := ini.Load(content) + if err != nil { + t.Fatal(err) + } + + if iniFile.HasSection("config") { + t.Fatal("precondition: [config] should not exist before EnsureParentSections") + } + if iniFile.HasSection("role") { + t.Fatal("precondition: [role] should not exist before EnsureParentSections") + } + + credentialexchange.EnsureParentSections(iniFile) + + if !iniFile.HasSection("config") { + t.Error("[config] parent section was not created") + } + if !iniFile.HasSection("role") { + t.Error("[role] parent section was not created") + } +} diff --git a/internal/credentialexchange/secret.go b/internal/credentialexchange/secret.go index d78c59e..2e26ce8 100644 --- a/internal/credentialexchange/secret.go +++ b/internal/credentialexchange/secret.go @@ -117,8 +117,8 @@ func (s *SecretStore) SaveAWSCredential(cred *AWSCredentials) error { func (s *SecretStore) ClearAll(cfg *ini.File) error { srvSections := []string{} - for _, v := range cfg.Section(INI_CONF_SECTION).ChildSections() { - srvSections = append(srvSections, strings.ReplaceAll(v.Name(), fmt.Sprintf("%s.", INI_CONF_SECTION), "")) + for _, v := range cfg.Section(INI_ROLE_SECTION).ChildSections() { + srvSections = append(srvSections, strings.ReplaceAll(v.Name(), fmt.Sprintf("%s.", INI_ROLE_SECTION), "")) } for _, v := range srvSections { diff --git a/internal/credentialexchange/secret_test.go b/internal/credentialexchange/secret_test.go index 6c08645..acf9cd0 100644 --- a/internal/credentialexchange/secret_test.go +++ b/internal/credentialexchange/secret_test.go @@ -134,17 +134,14 @@ func Test_SecretStore_AWSCredential_(t *testing.T) { for name, tt := range ttests { t.Run(name, func(t *testing.T) { - tmpDir, _ := os.MkdirTemp(os.TempDir(), "saml-cred-test") + tmpDir := t.TempDir() _ = os.WriteFile(path.Join(tmpDir, fmt.Sprintf(".%s.ini", credentialexchange.SELF_NAME)), []byte(` [role] [role.roleArn] name = "arn:aws:iam::111122342343:role/DevAdmin" `), 0777) - os.Setenv("HOME", tmpDir) - defer func() { - os.Clearenv() - os.RemoveAll(tmpDir) - }() + t.Setenv("HOME", tmpDir) + t.Setenv("USERPROFILE", tmpDir) crde, err := credentialexchange.NewSecretStore("roleArn", "namer", tmpDir, "test-user") if err != nil { @@ -211,18 +208,15 @@ func Test_SaveAwsCredential_with(t *testing.T) { } for name, tt := range ttests { t.Run(name, func(t *testing.T) { - tmpDir, _ := os.MkdirTemp(os.TempDir(), "saml-cred-test") + tmpDir := t.TempDir() iniFile := path.Join(tmpDir, fmt.Sprintf(".%s.ini", credentialexchange.SELF_NAME)) _ = os.WriteFile(iniFile, []byte(` [role] [role.someotherRole] name = "arn:aws:iam::111122342343:role/DevAdmin" `), 0777) - os.Setenv("HOME", tmpDir) - defer func() { - os.Clearenv() - os.RemoveAll(tmpDir) - }() + t.Setenv("HOME", tmpDir) + t.Setenv("USERPROFILE", tmpDir) crde, errInit := credentialexchange.NewSecretStore("roleArn", "namer", tmpDir, "test-user") @@ -293,18 +287,15 @@ func Test_ClearAll_with(t *testing.T) { } for name, tt := range ttests { t.Run(name, func(t *testing.T) { - tmpDir, _ := os.MkdirTemp(os.TempDir(), "saml-cred-test-*") + tmpDir := t.TempDir() iniFile := path.Join(tmpDir, fmt.Sprintf(".%s.ini", credentialexchange.SELF_NAME)) _ = os.WriteFile(iniFile, []byte(` [role] [role.someotherRole] name = "arn:aws:iam::111122342343:role/DevAdmin" `), 0777) - os.Setenv("HOME", tmpDir) - defer func() { - os.Clearenv() - os.RemoveAll(tmpDir) - }() + t.Setenv("HOME", tmpDir) + t.Setenv("USERPROFILE", tmpDir) crde, errInit := credentialexchange.NewSecretStore("roleArn", "namer", tmpDir, "test-user") diff --git a/internal/web/web.go b/internal/web/web.go index 6e995e3..246d852 100755 --- a/internal/web/web.go +++ b/internal/web/web.go @@ -12,6 +12,7 @@ import ( "github.com/DevLabFoundry/aws-cli-auth/internal/credentialexchange" "github.com/go-rod/rod" + "github.com/go-rod/rod/lib/defaults" "github.com/go-rod/rod/lib/launcher" "github.com/go-rod/rod/lib/utils" ) @@ -25,7 +26,14 @@ type WebConfig struct { // CustomChromeExecutable can point to a chromium like browser executable // e.g. chrome, chromium, brave, edge, (any other chromium based browser) CustomChromeExecutable string - datadir string + // BrowserWSEndpoint connects to an already-running browser via its CDP WebSocket URL + // instead of launching a new one. Takes precedence over rod's native -rod=url= flag. + // Useful in WSL: start Chrome on the Windows host with + // chrome.exe --remote-debugging-port=9222 + // then obtain the URL from http://localhost:9222/json/version (webSocketDebuggerUrl) + // and either pass -rod=url= to go test or call WithBrowserWSEndpoint(). + BrowserWSEndpoint string + datadir string // timeout value in seconds timeout int32 headless bool @@ -34,10 +42,12 @@ type WebConfig struct { } func NewWebConf(datadir string) *WebConfig { + wsEndpoint := os.Getenv("ROD_BROWSER_WS_URL") return &WebConfig{ - datadir: datadir, - headless: false, - timeout: 120, + datadir: datadir, + headless: false, + timeout: 120, + BrowserWSEndpoint: wsEndpoint, } } @@ -61,6 +71,14 @@ func (wc *WebConfig) WithCustomExecutable(browserPath string) *WebConfig { return wc } +// WithBrowserWSEndpoint connects to an already-running browser via its CDP WebSocket URL +// rather than launching a new one. See WebConfig.BrowserWSEndpoint for details. +// Alternatively pass -rod=url= to go test to use rod's native flag. +func (wc *WebConfig) WithBrowserWSEndpoint(wsURL string) *WebConfig { + wc.BrowserWSEndpoint = wsURL + return wc +} + type Web struct { conf *WebConfig launcher *launcher.Launcher @@ -70,24 +88,39 @@ type Web struct { // New returns an initialised instance of Web struct func New(ctx context.Context, conf *WebConfig) (*Web, error) { - l := BuildLauncher(ctx, conf) + // Prefer an explicitly configured endpoint, then rod's native defaults.URL + // (set via -rod=url= when running go test). + wsEndpoint := conf.BrowserWSEndpoint + if wsEndpoint == "" { + wsEndpoint = defaults.URL + } - url, err := l.Launch() - if err != nil { - return nil, err + var l *launcher.Launcher + var controlURL string + + if wsEndpoint != "" { + // Connect to an already-running browser (e.g. Chrome on the Windows host + // when running inside WSL). No local launcher is needed. + controlURL = wsEndpoint + } else { + var err error + l = BuildLauncher(ctx, conf) + controlURL, err = l.Launch() + if err != nil { + return nil, err + } } + browser := rod.New(). - ControlURL(url). + ControlURL(controlURL). MustConnect().NoDefaultDevice() - web := &Web{ + return &Web{ conf: conf, launcher: l, browser: browser, ctx: ctx, - } - - return web, nil + }, nil } func BuildLauncher(ctx context.Context, conf *WebConfig) *launcher.Launcher { @@ -234,13 +267,18 @@ func (web *Web) MustClose() { // this ensures that the browser remembers the credentials // and anything else done during the sign up process - e.g. extension installation // web.launcher.Cleanup() - // swallows errors here - until a structured logger - _ = web.browser.Close() - utils.Sleep(0.5) - web.launcher.Kill() - // remove process just in case - // os.Process is cross platform safe way to remove a process - if osprocess, err := os.FindProcess(web.launcher.PID()); err == nil && osprocess != nil { - _ = osprocess.Kill() + + // Only close the browser if we launched it ourselves. + // When connected to an existing browser (launcher == nil, e.g. via ROD_BROWSER_WS_URL + // or -rod=url=...), calling browser.Close() would destroy the remote browser window. + if web.launcher != nil { + _ = web.browser.Close() + utils.Sleep(0.5) + web.launcher.Kill() + // remove process just in case + // os.Process is cross platform safe way to remove a process + if osprocess, err := os.FindProcess(web.launcher.PID()); err == nil && osprocess != nil { + _ = osprocess.Kill() + } } } diff --git a/internal/web/web_test.go b/internal/web/web_test.go index 42aa80d..1e74762 100644 --- a/internal/web/web_test.go +++ b/internal/web/web_test.go @@ -83,7 +83,6 @@ SAMLResponse=dsicisud99u2ubf92e9euhre&RelayState= } func Test_WebUI_with_succesful_saml(t *testing.T) { - ts := httptest.NewServer(mockIdpHandler(t)) defer ts.Close() conf := credentialexchange.CredentialConfig{BaseConfig: credentialexchange.BaseConfig{}} @@ -110,7 +109,6 @@ func Test_WebUI_with_succesful_saml(t *testing.T) { } func Test_WebUI_timeout_and_return_error(t *testing.T) { - ts := httptest.NewServer(mockIdpHandler(t)) defer ts.Close() conf := credentialexchange.CredentialConfig{BaseConfig: credentialexchange.BaseConfig{}} @@ -134,10 +132,6 @@ func Test_WebUI_timeout_and_return_error(t *testing.T) { } } -func Test_ClearCache(t *testing.T) { - t.Skip("no longer relevant") -} - func mockSsoHandler(t *testing.T) http.Handler { t.Helper() mux := http.NewServeMux() @@ -169,7 +163,6 @@ func mockSsoHandler(t *testing.T) http.Handler { } func Test_WebUI_with_succesful_ssoLogin(t *testing.T) { - ts := httptest.NewServer(mockSsoHandler(t)) defer ts.Close() conf := credentialexchange.CredentialConfig{ @@ -201,7 +194,6 @@ func Test_WebUI_with_succesful_ssoLogin(t *testing.T) { } func Test_WebUI_with_timeout_ssoLogin(t *testing.T) { - ts := httptest.NewServer(mockSsoHandler(t)) defer ts.Close() conf := credentialexchange.CredentialConfig{ @@ -257,16 +249,4 @@ func Test_Web_BuildLauncher(t *testing.T) { } }) } - - t.Run("default browser is returned when no custom binary specified", func(t *testing.T) { - // for people running this locally without a default chrome/chromium installed this will potentially fail - // - // run the tests in the `eirctl run unit:test:run` - // - got := web.BuildLauncher(context.TODO(), &web.WebConfig{CustomChromeExecutable: ""}) - bin := got.Get("rod-bin") - if len(bin) < 1 { - t.Fatal("got no binary paths") - } - }) }