diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index e057bae..189060f 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -21,18 +21,18 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' cache: false - name: Lint - uses: golangci/golangci-lint-action@v7 + uses: golangci/golangci-lint-action@v8 with: - args: --build-tags integration -D protogetter --timeout=5m + args: --build-tags integration --timeout=5m - name: Test run: | @@ -58,10 +58,10 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: go-version-file: 'go.mod' @@ -117,7 +117,7 @@ jobs: cp bin/* metal/${TARGET_BINARY_LOCATION}/ - name: Upload Release Asset - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 with: token: ${{ secrets.GITHUB_TOKEN }} files: | diff --git a/.github/workflows/release-drafter.yaml b/.github/workflows/release-drafter.yaml index 0a81725..44f017a 100644 --- a/.github/workflows/release-drafter.yaml +++ b/.github/workflows/release-drafter.yaml @@ -10,6 +10,6 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: release-drafter/release-drafter@v5 + - uses: release-drafter/release-drafter@v6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/cmd/admin/v1/token.go b/cmd/admin/v1/token.go index 4c7291c..8464989 100644 --- a/cmd/admin/v1/token.go +++ b/cmd/admin/v1/token.go @@ -58,7 +58,7 @@ func (c *token) List() ([]*apiv2.Token, error) { req := &adminv2.TokenServiceListRequest{} if viper.IsSet("user") { - req.UserId = pointer.Pointer(viper.GetString("user")) + req.User = pointer.Pointer(viper.GetString("user")) } resp, err := c.c.Client.Adminv2().Token().List(ctx, connect.NewRequest(req)) @@ -82,8 +82,8 @@ func (c *token) Delete(id string) (*apiv2.Token, error) { } req := &adminv2.TokenServiceRevokeRequest{ - Uuid: id, - UserId: viper.GetString("user"), + Uuid: id, + User: viper.GetString("user"), } _, err := c.c.Client.Adminv2().Token().Revoke(ctx, connect.NewRequest(req)) diff --git a/cmd/api/v1/project.go b/cmd/api/v1/project.go index a4fc714..1087c38 100644 --- a/cmd/api/v1/project.go +++ b/cmd/api/v1/project.go @@ -402,8 +402,8 @@ func (c *project) removeMember(args []string) error { defer cancel() _, err = c.c.Client.Apiv2().Project().RemoveMember(ctx, connect.NewRequest(&apiv2.ProjectServiceRemoveMemberRequest{ - Project: c.c.GetProject(), - MemberId: member, + Project: c.c.GetProject(), + Member: member, })) if err != nil { return fmt.Errorf("failed to remove member from project: %w", err) @@ -424,9 +424,9 @@ func (c *project) updateMember(args []string) error { defer cancel() resp, err := c.c.Client.Apiv2().Project().UpdateMember(ctx, connect.NewRequest(&apiv2.ProjectServiceUpdateMemberRequest{ - Project: c.c.GetProject(), - MemberId: member, - Role: apiv2.ProjectRole(apiv2.ProjectRole_value[viper.GetString("role")]), + Project: c.c.GetProject(), + Member: member, + Role: apiv2.ProjectRole(apiv2.ProjectRole_value[viper.GetString("role")]), })) if err != nil { return fmt.Errorf("failed to update member: %w", err) diff --git a/cmd/api/v1/tenant.go b/cmd/api/v1/tenant.go index d7bc015..8893597 100644 --- a/cmd/api/v1/tenant.go +++ b/cmd/api/v1/tenant.go @@ -257,8 +257,7 @@ func (c *tenant) createRequestFromCLI() (*apiv2.TenantServiceCreateRequest, erro Name: viper.GetString("name"), Description: pointer.PointerOrNil(viper.GetString("description")), Email: pointer.PointerOrNil(viper.GetString("email")), - AvatarUrl: pointer.PointerOrNil(viper.GetString("phone")), - PhoneNumber: pointer.PointerOrNil(viper.GetString("avatar-url")), + AvatarUrl: pointer.PointerOrNil(viper.GetString("avatar-url")), }, nil } @@ -398,8 +397,8 @@ func (c *tenant) removeMember(args []string) error { defer cancel() _, err = c.c.Client.Apiv2().Tenant().RemoveMember(ctx, connect.NewRequest(&apiv2.TenantServiceRemoveMemberRequest{ - Login: tenant, - MemberId: member, + Login: tenant, + Member: member, })) if err != nil { return fmt.Errorf("failed to remove member from tenant: %w", err) @@ -425,9 +424,9 @@ func (c *tenant) updateMember(args []string) error { defer cancel() resp, err := c.c.Client.Apiv2().Tenant().UpdateMember(ctx, connect.NewRequest(&apiv2.TenantServiceUpdateMemberRequest{ - Login: tenant, - MemberId: member, - Role: apiv2.TenantRole(apiv2.TenantRole_value[viper.GetString("role")]), + Login: tenant, + Member: member, + Role: apiv2.TenantRole(apiv2.TenantRole_value[viper.GetString("role")]), })) if err != nil { return fmt.Errorf("failed to update member: %w", err) diff --git a/cmd/config/config.go b/cmd/config/config.go index 6e53fcf..965542b 100644 --- a/cmd/config/config.go +++ b/cmd/config/config.go @@ -51,22 +51,6 @@ func (c *Config) NewRequestContext() (context.Context, context.CancelFunc) { return context.WithTimeout(context.Background(), *timeout) } -func HelpTemplate() string { - return `Here is how an template configuration looks like: -~/.metal-stack/config.yaml ---- -current: dev -previous: prod -contexts: - - name: dev - api-token: - default-project: dev-project - - name: prod - api-token: - default-project: prod-project -` -} - func DefaultConfigDirectory() (string, error) { h, err := os.UserHomeDir() if err != nil { @@ -136,3 +120,10 @@ func (c *Config) GetApiURL() string { // fallback to the default specified by viper return viper.GetString("api-url") } + +func (c *Config) GetProvider() string { + if viper.IsSet("provider") { + return viper.GetString("provider") + } + return c.Context.Provider +} diff --git a/cmd/config/context.go b/cmd/config/context.go index 33a1a51..2ba9110 100644 --- a/cmd/config/context.go +++ b/cmd/config/context.go @@ -29,12 +29,11 @@ type Context struct { Token string `json:"api-token"` DefaultProject string `json:"default-project"` Timeout *time.Duration `json:"timeout,omitempty"` + Provider string `json:"provider"` } func (cs *Contexts) Get(name string) (*Context, bool) { for _, context := range cs.Contexts { - context := context - if context.Name == name { return context, true } @@ -44,22 +43,12 @@ func (cs *Contexts) Get(name string) (*Context, bool) { } func (cs *Contexts) List() []*Context { - var res []*Context - - for _, context := range cs.Contexts { - context := context - - res = append(res, context) - } - - return res + return append([]*Context{}, cs.Contexts...) } func (cs *Contexts) Validate() error { names := map[string]bool{} for _, context := range cs.Contexts { - context := context - names[context.Name] = true } @@ -132,10 +121,12 @@ func (c *Config) MustDefaultContext() Context { if err != nil { return defaultCtx() } + ctx, ok := ctxs.Get(ctxs.CurrentContext) if !ok { return defaultCtx() } + return *ctx } @@ -153,7 +144,6 @@ func (c *Config) ContextListCompletion(cmd *cobra.Command, args []string, toComp } var names []string for _, ctx := range ctxs.Contexts { - ctx := ctx names = append(names, ctx.Name) } return names, cobra.ShellCompDirectiveNoFileComp diff --git a/cmd/context.go b/cmd/context.go index b047571..99d654f 100644 --- a/cmd/context.go +++ b/cmd/context.go @@ -26,7 +26,6 @@ func newContextCmd(c *config.Config) *cobra.Command { Aliases: []string{"ctx"}, Short: "manage cli contexts", Long: "you can switch back and forth contexts with \"-\"", - Example: config.HelpTemplate(), RunE: func(cmd *cobra.Command, args []string) error { if len(args) == 0 { return w.list() @@ -92,6 +91,7 @@ func newContextCmd(c *config.Config) *cobra.Command { contextAddCmd.Flags().String("default-project", "", "sets a default project to act on") contextAddCmd.Flags().Duration("timeout", 0, "sets a default request timeout") contextAddCmd.Flags().Bool("activate", false, "immediately switches to the new context") + contextAddCmd.Flags().String("provider", "", "sets the login provider for this context") genericcli.Must(contextAddCmd.MarkFlagRequired("api-token")) @@ -108,6 +108,7 @@ func newContextCmd(c *config.Config) *cobra.Command { contextUpdateCmd.Flags().String("default-project", "", "sets a default project to act on") contextUpdateCmd.Flags().Duration("timeout", 0, "sets a default request timeout") contextUpdateCmd.Flags().Bool("activate", false, "immediately switches to the new context") + contextUpdateCmd.Flags().String("provider", "", "sets the login provider for this context") genericcli.Must(contextUpdateCmd.RegisterFlagCompletionFunc("default-project", c.Completion.ProjectListCompletion)) @@ -171,6 +172,7 @@ func (c *ctx) add(args []string) error { Token: viper.GetString("api-token"), DefaultProject: viper.GetString("default-project"), Timeout: pointer.PointerOrNil(viper.GetDuration("timeout")), + Provider: viper.GetString("provider"), } ctxs.Contexts = append(ctxs.Contexts, ctx) @@ -218,6 +220,9 @@ func (c *ctx) update(args []string) error { if viper.IsSet("timeout") { ctx.Timeout = pointer.PointerOrNil(viper.GetDuration("timeout")) } + if viper.IsSet("provider") { + ctx.Provider = viper.GetString("provider") + } if viper.GetBool("activate") { ctxs.PreviousContext = ctxs.CurrentContext ctxs.CurrentContext = ctx.Name diff --git a/cmd/login.go b/cmd/login.go index da75063..1a44670 100644 --- a/cmd/login.go +++ b/cmd/login.go @@ -14,8 +14,10 @@ import ( apiv2 "github.com/metal-stack/api/go/metalstack/api/v2" "github.com/metal-stack/cli/cmd/config" "github.com/metal-stack/metal-lib/pkg/genericcli" + "github.com/metal-stack/metal-lib/pkg/pointer" "github.com/spf13/cobra" "github.com/spf13/viper" + "google.golang.org/protobuf/types/known/durationpb" ) type login struct { @@ -36,15 +38,18 @@ func newLoginCmd(c *config.Config) *cobra.Command { } loginCmd.Flags().String("provider", "oidc", "the provider used to login with") - loginCmd.Flags().String("context-name", "", "the context into which the token gets injected, if not specified it uses the current context or creates a context named default in case there is no current context set") + loginCmd.Flags().String("context", "", "the context into which the token gets injected, if not specified it uses the current context or creates a context named default in case there is no current context set") + loginCmd.Flags().String("admin-role", "", "operators can use this flag to issue an admin token with the token retrieved from login and store this into context") + genericcli.Must(loginCmd.Flags().MarkHidden("admin-role")) genericcli.Must(loginCmd.RegisterFlagCompletionFunc("provider", cobra.FixedCompletions([]string{"oidc"}, cobra.ShellCompDirectiveNoFileComp))) + genericcli.Must(loginCmd.RegisterFlagCompletionFunc("admin-role", c.Completion.TokenAdminRoleCompletion)) return loginCmd } func (l *login) login() error { - provider := viper.GetString("provider") + provider := l.c.GetProvider() if provider == "" { return errors.New("provider must be specified") } @@ -55,22 +60,26 @@ func (l *login) login() error { } ctxName := ctxs.CurrentContext - if viper.IsSet("context-name") { - ctxName = viper.GetString("context-name") + if viper.IsSet("context") { + ctxName = viper.GetString("context") } - ctx, ok := ctxs.Get(ctxName) if !ok { - defaultCtx := l.c.MustDefaultContext() - defaultCtx.Name = "default" - - ctxs.PreviousContext = ctxs.CurrentContext - ctxs.CurrentContext = ctxName + newCtx := l.c.MustDefaultContext() + newCtx.Name = "default" + if viper.IsSet("context") { + newCtx.Name = viper.GetString("context") + } + newCtx.ApiURL = pointer.Pointer(l.c.GetApiURL()) + ctxs.Contexts = append(ctxs.Contexts, &newCtx) + ctx = &newCtx + } - ctxs.Contexts = append(ctxs.Contexts, &defaultCtx) + ctx.Provider = provider - ctx = &defaultCtx - } + // switch into new context + ctxs.PreviousContext = ctxs.CurrentContext + ctxs.CurrentContext = ctx.Name tokenChan := make(chan string) @@ -114,6 +123,24 @@ func (l *login) login() error { return errors.New("no token was retrieved") } + if viper.IsSet("admin-role") { + mc, err := newApiClient(l.c.GetApiURL(), token) + if err != nil { + return err + } + + tokenResp, err := mc.Apiv2().Token().Create(context.Background(), connect.NewRequest(&apiv2.TokenServiceCreateRequest{ + Description: "admin access issues by metal cli", + Expires: durationpb.New(3 * time.Hour), + AdminRole: pointer.Pointer(apiv2.AdminRole((apiv2.AdminRole_value[viper.GetString("admin-role")]))), + })) + if err != nil { + return fmt.Errorf("unable to issue admin token: %w", err) + } + + token = tokenResp.Msg.Secret + } + ctx.Token = token if ctx.DefaultProject == "" { diff --git a/cmd/sorters/token.go b/cmd/sorters/token.go index 86e1243..27cc738 100644 --- a/cmd/sorters/token.go +++ b/cmd/sorters/token.go @@ -11,7 +11,7 @@ func TokenSorter() *multisort.Sorter[*apiv2.Token] { return multisort.Compare(a.Uuid, b.Uuid, descending) }, "user": func(a, b *apiv2.Token, descending bool) multisort.CompareResult { - return multisort.Compare(a.UserId, b.UserId, descending) + return multisort.Compare(a.User, b.User, descending) }, "type": func(a, b *apiv2.Token, descending bool) multisort.CompareResult { return multisort.Compare(a.TokenType.String(), b.TokenType.String(), descending) diff --git a/cmd/tableprinters/context.go b/cmd/tableprinters/context.go index 7a56849..3cafaae 100644 --- a/cmd/tableprinters/context.go +++ b/cmd/tableprinters/context.go @@ -3,20 +3,37 @@ package tableprinters import ( "github.com/fatih/color" "github.com/metal-stack/cli/cmd/config" + "github.com/metal-stack/metal-lib/pkg/pointer" + "github.com/spf13/viper" ) func (t *TablePrinter) ContextTable(data *config.Contexts, wide bool) ([]string, [][]string, error) { var ( - header = []string{"", "Name", "Default Project"} + header = []string{"", "Name", "Provider", "Default Project"} rows [][]string ) + if wide { + header = append(header, "API URL") + } + for _, c := range data.Contexts { active := "" if c.Name == data.CurrentContext { active = color.GreenString("✔") } - rows = append(rows, []string{active, c.Name, c.DefaultProject}) + + row := []string{active, c.Name, c.Provider, c.DefaultProject} + if wide { + url := pointer.SafeDeref(c.ApiURL) + if url == "" { + url = viper.GetString("api-url") + } + + row = append(row, url) + } + + rows = append(rows, row) } return header, rows, nil diff --git a/cmd/tableprinters/token.go b/cmd/tableprinters/token.go index c5a4712..3f29f26 100644 --- a/cmd/tableprinters/token.go +++ b/cmd/tableprinters/token.go @@ -27,7 +27,7 @@ func (t *TablePrinter) TokenTable(data []*apiv2.Token, _ bool) ([]string, [][]st token.TokenType.String(), token.Uuid, admin, - token.UserId, + token.User, token.Description, strconv.Itoa(len(token.TenantRoles) + len(token.ProjectRoles)), strconv.Itoa(len(token.Permissions)), diff --git a/docs/metalctlv2_context.md b/docs/metalctlv2_context.md index bc03dfa..b07774e 100644 --- a/docs/metalctlv2_context.md +++ b/docs/metalctlv2_context.md @@ -10,24 +10,6 @@ you can switch back and forth contexts with "-" metalctlv2 context [flags] ``` -### Examples - -``` -Here is how an template configuration looks like: -~/.metal-stack/config.yaml ---- -current: dev -previous: prod -contexts: - - name: dev - api-token: - default-project: dev-project - - name: prod - api-token: - default-project: prod-project - -``` - ### Options ``` diff --git a/docs/metalctlv2_context_add.md b/docs/metalctlv2_context_add.md index 8382482..d60a35c 100644 --- a/docs/metalctlv2_context_add.md +++ b/docs/metalctlv2_context_add.md @@ -14,6 +14,7 @@ metalctlv2 context add [flags] --api-url string sets the api-url for this context --default-project string sets a default project to act on -h, --help help for add + --provider string sets the login provider for this context --timeout duration sets a default request timeout ``` diff --git a/docs/metalctlv2_context_update.md b/docs/metalctlv2_context_update.md index e56e040..0908bd5 100644 --- a/docs/metalctlv2_context_update.md +++ b/docs/metalctlv2_context_update.md @@ -14,6 +14,7 @@ metalctlv2 context update [flags] --api-url string sets the api-url for this context --default-project string sets a default project to act on -h, --help help for update + --provider string sets the login provider for this context --timeout duration sets a default request timeout ``` diff --git a/docs/metalctlv2_login.md b/docs/metalctlv2_login.md index 86857e1..7315df6 100644 --- a/docs/metalctlv2_login.md +++ b/docs/metalctlv2_login.md @@ -9,9 +9,9 @@ metalctlv2 login [flags] ### Options ``` - --context-name string the context into which the token gets injected, if not specified it uses the current context or creates a context named default in case there is no current context set - -h, --help help for login - --provider string the provider used to login with (default "oidc") + --context string the context into which the token gets injected, if not specified it uses the current context or creates a context named default in case there is no current context set + -h, --help help for login + --provider string the provider used to login with (default "oidc") ``` ### Options inherited from parent commands diff --git a/go.mod b/go.mod index 0172e84..6b56d03 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/metal-stack/cli -go 1.24.0 +go 1.25 require ( bou.ke/monkey v1.0.2 @@ -8,22 +8,21 @@ require ( github.com/dustin/go-humanize v1.0.1 github.com/fatih/color v1.18.0 github.com/google/go-cmp v0.7.0 - github.com/metal-stack/api v0.0.11 - github.com/metal-stack/metal-lib v0.23.3 + github.com/metal-stack/api v0.0.19 + github.com/metal-stack/metal-lib v0.23.5 github.com/metal-stack/v v1.0.3 - github.com/olekukonko/tablewriter v1.0.9 - github.com/spf13/afero v1.14.0 - github.com/spf13/cobra v1.9.1 - github.com/spf13/pflag v1.0.7 - github.com/spf13/viper v1.20.1 - github.com/stretchr/testify v1.10.0 - golang.org/x/net v0.43.0 - google.golang.org/protobuf v1.36.7 + github.com/spf13/afero v1.15.0 + github.com/spf13/cobra v1.10.1 + github.com/spf13/pflag v1.0.10 + github.com/spf13/viper v1.21.0 + github.com/stretchr/testify v1.11.1 + golang.org/x/net v0.44.0 + google.golang.org/protobuf v1.36.9 sigs.k8s.io/yaml v1.6.0 ) require ( - buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.7-20250717185734-6c6e0d3c608e.1 // indirect + buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.9-20250717185734-6c6e0d3c608e.1 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.7 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect @@ -45,19 +44,21 @@ require ( github.com/oklog/ulid v1.3.1 // indirect github.com/olekukonko/errors v1.1.0 // indirect github.com/olekukonko/ll v0.0.9 // indirect + github.com/olekukonko/tablewriter v1.0.9 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/sagikazarmark/locafero v0.10.0 // indirect + github.com/sagikazarmark/locafero v0.11.0 // indirect github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect - github.com/spf13/cast v1.9.2 // indirect + github.com/spf13/cast v1.10.0 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect go.mongodb.org/mongo-driver v1.17.4 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/sys v0.35.0 // indirect - golang.org/x/text v0.28.0 // indirect + go.yaml.in/yaml/v3 v3.0.4 // indirect + golang.org/x/sys v0.36.0 // indirect + golang.org/x/text v0.29.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/apimachinery v0.33.3 // indirect diff --git a/go.sum b/go.sum index 9449017..654f5c3 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ bou.ke/monkey v1.0.2 h1:kWcnsrCNUatbxncxR/ThdYqbytgOIArtYWqcQLQzKLI= bou.ke/monkey v1.0.2/go.mod h1:OqickVX3tNx6t33n1xvtTtu85YN5s6cKwVug+oHMaIA= -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.7-20250717185734-6c6e0d3c608e.1 h1:/AZH8sVB6LHv8G+hZlAMCP31NevnesHwYgnlgS5Vt14= -buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.7-20250717185734-6c6e0d3c608e.1/go.mod h1:eva/VCrd8X7xuJw+JtwCEyrCKiRRASukFqmirnWBvFU= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.9-20250717185734-6c6e0d3c608e.1 h1:u98oQG8CHYBrOWrYdqbyNpKz4Pw02ssv03DsTInnXn8= +buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.9-20250717185734-6c6e0d3c608e.1/go.mod h1:aY3zbkNan5F+cGm9lITDP6oxJIwu0dn9KjJuJjWaHkg= connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw= connectrpc.com/connect v1.18.1/go.mod h1:0292hj1rnx8oFrStN7cB4jjVBeqs+Yx5yDIC2prWDO8= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= @@ -53,10 +53,10 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/metal-stack/api v0.0.11 h1:aWMT1WTCIRm+DZFWZGUI08M/9LY2XIdtJZA5zJ/o1zo= -github.com/metal-stack/api v0.0.11/go.mod h1:GZEuAwwZXo1szv+0iLstU9sSra8gOIwSiquuRtGWxWo= -github.com/metal-stack/metal-lib v0.23.3 h1:ZcouyuCXy2bMZn+CB0yx1JdAl8SEkfjmlzNLyrmD/kA= -github.com/metal-stack/metal-lib v0.23.3/go.mod h1:29JMehA4KSeDovG9y1xgQkdc5pAk2/MBvOufRNSk5Bc= +github.com/metal-stack/api v0.0.19 h1:RVfrJqixKwLlpKZH/Mk9sgVS6ghejQhxSzISShwbvwM= +github.com/metal-stack/api v0.0.19/go.mod h1:6EHxH4Jhe6TbPcTfOJmb+cpeZbo0oIRalECYkq2jgPc= +github.com/metal-stack/metal-lib v0.23.5 h1:ozrkB3DNr3Cqn8nkBvmzc/KKpYqC1j1mv2OVOj8i7Ac= +github.com/metal-stack/metal-lib v0.23.5/go.mod h1:7uyHIrE19dkLwCZyeh2jmd7IEq5pEpzrzUGLoMN1eqY= github.com/metal-stack/v v1.0.3 h1:Sh2oBlnxrCUD+mVpzfC8HiqL045YWkxs0gpTvkjppqs= github.com/metal-stack/v v1.0.3/go.mod h1:YTahEu7/ishwpYKnp/VaW/7nf8+PInogkfGwLcGPdXg= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -80,42 +80,42 @@ github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sagikazarmark/locafero v0.10.0 h1:FM8Cv6j2KqIhM2ZK7HZjm4mpj9NBktLgowT1aN9q5Cc= -github.com/sagikazarmark/locafero v0.10.0/go.mod h1:Ieo3EUsjifvQu4NZwV5sPd4dwvu0OCgEQV7vjc9yDjw= +github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc= +github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw= github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U= -github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA= -github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo= -github.com/spf13/cast v1.9.2 h1:SsGfm7M8QOFtEzumm7UZrZdLLquNdzFYfIbEXntcFbE= -github.com/spf13/cast v1.9.2/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= -github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= -github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= -github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= -github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.20.1 h1:ZMi+z/lvLyPSCoNtFCpqjy0S4kPbirhpTMwl8BkW9X4= -github.com/spf13/viper v1.20.1/go.mod h1:P9Mdzt1zoHIG8m2eZQinpiBjo6kCmZSKBClNNqjJvu4= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= +github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= +github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= +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/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/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= +github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= 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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +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/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw= go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= -go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE= -go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= -golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= -golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= +go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I= +golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= -golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= -google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= -google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= +google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= +google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=