Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
225 changes: 225 additions & 0 deletions auth_providers/auth_credentials.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
// Copyright 2026 Keyfactor
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package auth_providers

import (
"fmt"
"strings"
)

// AuthMethod is the credential family that satisfies a Keyfactor auth
// request. Returned by AuthCreds.Validate.
type AuthMethod string

const (
// AuthMethodUnset means no complete credential tuple was found.
AuthMethodUnset AuthMethod = ""
// AuthMethodBasic requires Username + Password (and optionally Domain).
AuthMethodBasic AuthMethod = "basic"
// AuthMethodOAuth2 requires ClientID + ClientSecret + TokenURL.
AuthMethodOAuth2 AuthMethod = "oauth2"
// AuthMethodToken requires AccessToken (a static bearer).
AuthMethodToken AuthMethod = "token"
// AuthMethodKerberos requires at least one of:
// KerberosKeytab,
// KerberosCCache,
// (Username + Password + KerberosRealm).
AuthMethodKerberos AuthMethod = "kerberos"
)

// AuthCreds is the auth-only view of a Server, decoupled from Command
// target fields (Host/Port/APIPath). It lets callers validate
// credentials independently of whether they're targeting Command,
// ACME, or anything else.
//
// AuthCreds is intentionally a flat struct so it round-trips cleanly
// through Viper / mapstructure. The loader subpackage uses it for
// sub-block override merging.
type AuthCreds struct {
// AuthType is an optional explicit method selector ("basic",
// "oauth2", "token", "kerberos"). When set it disambiguates
// otherwise-overlapping inputs (e.g. an OAuth2 client_id and a
// static AccessToken set on the same profile). When unset,
// Validate infers the method from which fields are populated.
AuthType string `mapstructure:"auth_type" json:"auth_type,omitempty" yaml:"auth_type,omitempty"`

// Basic
Username string `mapstructure:"username" json:"username,omitempty" yaml:"username,omitempty"`
Password string `mapstructure:"password" json:"password,omitempty" yaml:"password,omitempty"`
Domain string `mapstructure:"domain" json:"domain,omitempty" yaml:"domain,omitempty"`

// OAuth2 client credentials
ClientID string `mapstructure:"client_id" json:"client_id,omitempty" yaml:"client_id,omitempty"`
ClientSecret string `mapstructure:"client_secret" json:"client_secret,omitempty" yaml:"client_secret,omitempty"`
TokenURL string `mapstructure:"token_url" json:"token_url,omitempty" yaml:"token_url,omitempty"`
Scopes []string `mapstructure:"scopes" json:"scopes,omitempty" yaml:"scopes,omitempty"`
Audience string `mapstructure:"audience" json:"audience,omitempty" yaml:"audience,omitempty"`

// Static bearer
AccessToken string `mapstructure:"access_token" json:"access_token,omitempty" yaml:"access_token,omitempty"`

// Kerberos
KerberosRealm string `mapstructure:"kerberos_realm" json:"kerberos_realm,omitempty" yaml:"kerberos_realm,omitempty"`
KerberosKeytab string `mapstructure:"kerberos_keytab" json:"kerberos_keytab,omitempty" yaml:"kerberos_keytab,omitempty"`
KerberosConfig string `mapstructure:"kerberos_config" json:"kerberos_config,omitempty" yaml:"kerberos_config,omitempty"`
KerberosCCache string `mapstructure:"kerberos_ccache" json:"kerberos_ccache,omitempty" yaml:"kerberos_ccache,omitempty"`
KerberosSPN string `mapstructure:"kerberos_spn" json:"kerberos_spn,omitempty" yaml:"kerberos_spn,omitempty"`
}

// AuthCredsFromServer extracts the credential fields from a Server into
// a standalone AuthCreds. Used by the loader to build the server-level
// view before applying per-tool sub-block overrides.
func AuthCredsFromServer(s *Server) *AuthCreds {
if s == nil {
return &AuthCreds{}
}
return &AuthCreds{
AuthType: s.AuthType,
Username: s.Username,
Password: s.Password,
Domain: s.Domain,
ClientID: s.ClientID,
ClientSecret: s.ClientSecret,
TokenURL: s.OAuthTokenUrl,
Scopes: append([]string(nil), s.Scopes...),
Audience: s.Audience,
AccessToken: s.AccessToken,
KerberosRealm: s.KerberosRealm,
KerberosKeytab: s.KerberosKeytab,
KerberosConfig: s.KerberosConfig,
KerberosCCache: s.KerberosCCache,
KerberosSPN: s.KerberosSPN,
}
}

// Validate reports whether the credentials form a complete tuple for
// some auth method, and returns the resolved method.
//
// Method selection rules (first match wins):
// 1. If AuthType is set, it forces the chosen method; all required
// fields for that method must be present.
// 2. Otherwise, the first method whose required fields are fully
// populated is selected.
//
// Validation is strict: a partially-populated method (e.g. ClientID
// without ClientSecret) returns an error naming the missing fields
// even when another method would have been complete. This catches
// configuration mistakes early.
func (a *AuthCreds) Validate() (AuthMethod, error) {
if a == nil {
return AuthMethodUnset, fmt.Errorf("auth credentials are nil")
}

// What's populated, by method.
hasBasic := a.Username != "" || a.Password != ""
hasOAuth2 := a.ClientID != "" || a.ClientSecret != "" || a.TokenURL != ""
hasToken := a.AccessToken != ""
hasKerberos := a.KerberosRealm != "" || a.KerberosKeytab != "" || a.KerberosCCache != "" || a.KerberosSPN != ""

// Forced by AuthType.
if a.AuthType != "" {
switch strings.ToLower(a.AuthType) {
case string(AuthMethodBasic):
return AuthMethodBasic, validateBasic(a)
case string(AuthMethodOAuth2):
return AuthMethodOAuth2, validateOAuth2(a)
case string(AuthMethodToken):
return AuthMethodToken, validateToken(a)
case string(AuthMethodKerberos):
return AuthMethodKerberos, validateKerberos(a)
default:
return AuthMethodUnset, fmt.Errorf("unknown auth_type %q (expected basic, oauth2, token, or kerberos)", a.AuthType)
}
}

// Strict-mode partial detection: if a method's first field is set
// but the rest are not, it's an error even if another method would
// have validated. This makes "I forgot client_secret" produce a
// clear message instead of silently falling through.
if hasOAuth2 {
if err := validateOAuth2(a); err != nil {
return AuthMethodUnset, err
}
return AuthMethodOAuth2, nil
}
if hasBasic {
if err := validateBasic(a); err != nil {
return AuthMethodUnset, err
}
return AuthMethodBasic, nil
}
if hasToken {
// Token only needs AccessToken; validateToken is just a
// non-empty check.
return AuthMethodToken, validateToken(a)
}
if hasKerberos {
if err := validateKerberos(a); err != nil {
return AuthMethodUnset, err
}
return AuthMethodKerberos, nil
}

return AuthMethodUnset, fmt.Errorf("no auth credentials configured (set username/password, client_id/client_secret/token_url, access_token, or a Kerberos tuple)")
}

func validateBasic(a *AuthCreds) error {
var missing []string
if a.Username == "" {
missing = append(missing, "username")
}
if a.Password == "" {
missing = append(missing, "password")
}
if len(missing) > 0 {
return fmt.Errorf("basic auth missing required field(s): %s", strings.Join(missing, ", "))
}
return nil
}

func validateOAuth2(a *AuthCreds) error {
var missing []string
if a.ClientID == "" {
missing = append(missing, "client_id")
}
if a.ClientSecret == "" {
missing = append(missing, "client_secret")
}
if a.TokenURL == "" {
missing = append(missing, "token_url")
}
if len(missing) > 0 {
return fmt.Errorf("oauth2 auth missing required field(s): %s", strings.Join(missing, ", "))
}
return nil
}

func validateToken(a *AuthCreds) error {
if a.AccessToken == "" {
return fmt.Errorf("token auth missing required field: access_token")
}
return nil
}

func validateKerberos(a *AuthCreds) error {
// Kerberos accepts any of: keytab, ccache, or username+password+realm.
if a.KerberosKeytab != "" || a.KerberosCCache != "" {
return nil
}
if a.Username != "" && a.Password != "" && a.KerberosRealm != "" {
return nil
}
return fmt.Errorf("kerberos auth requires one of: kerberos_keytab, kerberos_ccache, or (username + password + kerberos_realm)")
}
13 changes: 13 additions & 0 deletions auth_providers/command_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,19 @@ type Server struct {
KerberosConfig string `json:"kerberos_config,omitempty" yaml:"kerberos_config,omitempty"` // KerberosConfig is the path to krb5.conf.
KerberosCCache string `json:"kerberos_ccache,omitempty" yaml:"kerberos_ccache,omitempty"` // KerberosCCache is the path to the credential cache.
KerberosSPN string `json:"kerberos_spn,omitempty" yaml:"kerberos_spn,omitempty"` // KerberosSPN is the Service Principal Name.

// Extras holds per-tool sub-blocks decoded alongside the canonical
// fields. Populated by the loader subpackage when consumers register
// their tool namespaces. Direct access is uncommon — prefer
// loader.DecodeExtras(namespace, target).
//
// The `mapstructure:",remain"` tag tells mapstructure (used by Viper
// inside the loader) to put any keys it doesn't recognize from the
// parent struct into this map, preserving them across read/write
// cycles. The json/yaml `-` tags keep Extras out of the canonical
// wire format for the existing ReadConfig*/WriteConfig* paths; the
// loader handles sub-block serialization separately.
Extras map[string]any `json:"-" yaml:"-" mapstructure:",remain"`
}

// AuthProvider represents the authentication provider configuration.
Expand Down
11 changes: 11 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azsecrets v1.4.0
github.com/jcmturner/gokrb5/v8 v8.4.4
github.com/spf13/pflag v1.0.10
github.com/spf13/viper v1.21.0
github.com/stretchr/testify v1.11.1
golang.org/x/oauth2 v0.34.0
gopkg.in/yaml.v2 v2.4.0
Expand All @@ -31,6 +33,8 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.2.0 // indirect
github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/hashicorp/go-uuid v1.0.3 // indirect
Expand All @@ -40,8 +44,15 @@ require (
github.com/jcmturner/goidentity/v6 v6.0.1 // indirect
github.com/jcmturner/rpc/v2 v2.0.3 // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/sagikazarmark/locafero v0.11.0 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spf13/afero v1.15.0 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.47.0 // indirect
golang.org/x/net v0.49.0 // indirect
golang.org/x/sys v0.40.0 // indirect
Expand Down
41 changes: 26 additions & 15 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0 h1:JXg2dwJUmPB9JmtVmdEB16APJ7jurfbY5jnfXpJoRMc=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.20.0/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0 h1:fou+2+WFTib47nS+nz/ozhEBnvU96bKHy6LjRsY4E28=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.0/go.mod h1:t76Ruy8AHvUAC8GfMWJMa0ElSbuIcO03NLpynfbgsPA=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4=
Expand All @@ -19,8 +17,16 @@ github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQ
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/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
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/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
Expand Down Expand Up @@ -50,12 +56,26 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
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/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
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.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/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.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=
Expand All @@ -65,14 +85,14 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
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=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
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/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/crypto v0.47.0 h1:V6e3FRj+n4dbpw86FJ8Fv7XVOql7TEwpHapKoMJ/GO8=
golang.org/x/crypto v0.47.0/go.mod h1:ff3Y9VzzKbwSSEzWqJsJVBnWmRwRSHt/6Op5n9bQc4A=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
Expand All @@ -82,9 +102,6 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
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.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
Expand All @@ -98,9 +115,6 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
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.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
Expand All @@ -110,9 +124,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
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.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
Expand Down
Loading
Loading