Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37e467c105 |
No files matched your search
@@ -34,7 +34,7 @@ require (
|
|||||||
go.opentelemetry.io/otel v1.29.0 // indirect
|
go.opentelemetry.io/otel v1.29.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.29.0 // indirect
|
go.opentelemetry.io/otel/metric v1.29.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.29.0 // indirect
|
go.opentelemetry.io/otel/trace v1.29.0 // indirect
|
||||||
golang.org/x/sync v0.8.0 // indirect
|
golang.org/x/sync v0.10.0 // indirect
|
||||||
golang.org/x/time v0.6.0 // indirect
|
golang.org/x/time v0.6.0 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
||||||
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
||||||
@@ -55,10 +55,10 @@ require (
|
|||||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.9.0
|
||||||
golang.org/x/crypto v0.26.0 // indirect
|
golang.org/x/crypto v0.31.0 // indirect
|
||||||
golang.org/x/net v0.28.0 // indirect
|
golang.org/x/net v0.33.0 // indirect
|
||||||
golang.org/x/sys v0.24.0 // indirect
|
golang.org/x/sys v0.28.0 // indirect
|
||||||
golang.org/x/text v0.17.0 // indirect
|
golang.org/x/text v0.21.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
|
||||||
google.golang.org/grpc v1.66.0
|
google.golang.org/grpc v1.66.0
|
||||||
google.golang.org/protobuf v1.34.2
|
google.golang.org/protobuf v1.34.2
|
||||||
|
|||||||
@@ -215,8 +215,8 @@ go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ
|
|||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
||||||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
@@ -234,8 +234,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
|||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
|
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||||
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
|
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA=
|
golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA=
|
||||||
golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||||
@@ -243,18 +243,18 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
|
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||||
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||||
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U=
|
||||||
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
|||||||
@@ -119,17 +119,15 @@ func TestGetCredentialsConfig(t *testing.T) {
|
|||||||
Zone: "us-central-1a",
|
Zone: "us-central-1a",
|
||||||
},
|
},
|
||||||
expected: &Config{
|
expected: &Config{
|
||||||
Zone: "us-central-1a",
|
Zone: "us-central-1a",
|
||||||
Scopes: []string{defaultGCPScope},
|
Scopes: []string{defaultGCPScope},
|
||||||
validateServiceAccountKeyTimeout: defaultValidateServiceAccountKeyTimeout,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "nil attributes",
|
name: "nil attributes",
|
||||||
attrs: nil,
|
attrs: nil,
|
||||||
expected: &Config{
|
expected: &Config{
|
||||||
Scopes: []string{defaultGCPScope},
|
Scopes: []string{defaultGCPScope},
|
||||||
validateServiceAccountKeyTimeout: defaultValidateServiceAccountKeyTimeout,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -156,13 +154,12 @@ func TestGetCredentialsConfig(t *testing.T) {
|
|||||||
ClientEmail: "test@test.com",
|
ClientEmail: "test@test.com",
|
||||||
},
|
},
|
||||||
expected: &Config{
|
expected: &Config{
|
||||||
ProjectId: "test-project",
|
ProjectId: "test-project",
|
||||||
Zone: "us-central-1a",
|
Zone: "us-central-1a",
|
||||||
ClientEmail: "test@test.com",
|
ClientEmail: "test@test.com",
|
||||||
PrivateKey: "test-private-key",
|
PrivateKey: "test-private-key",
|
||||||
PrivateKeyId: "test-private-key-id",
|
PrivateKeyId: "test-private-key-id",
|
||||||
Scopes: []string{defaultGCPScope},
|
Scopes: []string{defaultGCPScope},
|
||||||
validateServiceAccountKeyTimeout: defaultValidateServiceAccountKeyTimeout,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -223,13 +220,12 @@ func TestGetCredentialsConfig(t *testing.T) {
|
|||||||
Zone: "us-central-1a",
|
Zone: "us-central-1a",
|
||||||
},
|
},
|
||||||
expected: &Config{
|
expected: &Config{
|
||||||
ProjectId: "test-project",
|
ProjectId: "test-project",
|
||||||
Zone: "us-central-1a",
|
Zone: "us-central-1a",
|
||||||
PrivateKey: "test-private-key",
|
PrivateKey: "test-private-key",
|
||||||
PrivateKeyId: "test-private-key-id",
|
PrivateKeyId: "test-private-key-id",
|
||||||
ClientEmail: "test@test.com",
|
ClientEmail: "test@test.com",
|
||||||
Scopes: []string{defaultGCPScope},
|
Scopes: []string{defaultGCPScope},
|
||||||
validateServiceAccountKeyTimeout: defaultValidateServiceAccountKeyTimeout,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -245,14 +241,13 @@ func TestGetCredentialsConfig(t *testing.T) {
|
|||||||
TargetServiceAccountId: "test-target-service-account",
|
TargetServiceAccountId: "test-target-service-account",
|
||||||
},
|
},
|
||||||
expected: &Config{
|
expected: &Config{
|
||||||
ProjectId: "test-project",
|
ProjectId: "test-project",
|
||||||
Zone: "us-central-1a",
|
Zone: "us-central-1a",
|
||||||
PrivateKey: "test-private-key",
|
PrivateKey: "test-private-key",
|
||||||
PrivateKeyId: "test-private-key-id",
|
PrivateKeyId: "test-private-key-id",
|
||||||
ClientEmail: "test@test.com",
|
ClientEmail: "test@test.com",
|
||||||
TargetServiceAccountId: "test-target-service-account",
|
TargetServiceAccountId: "test-target-service-account",
|
||||||
Scopes: []string{defaultGCPScope},
|
Scopes: []string{defaultGCPScope},
|
||||||
validateServiceAccountKeyTimeout: defaultValidateServiceAccountKeyTimeout,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,21 +41,17 @@ const (
|
|||||||
// and then controlling the service account's access by granting it IAM roles.
|
// and then controlling the service account's access by granting it IAM roles.
|
||||||
// https://cloud.google.com/compute/docs/access/service-accounts#scopes_best_practice
|
// https://cloud.google.com/compute/docs/access/service-accounts#scopes_best_practice
|
||||||
defaultGCPScope = "https://www.googleapis.com/auth/cloud-platform"
|
defaultGCPScope = "https://www.googleapis.com/auth/cloud-platform"
|
||||||
// defaultValidateServiceAccountKeyTimeout is the timeout for validating
|
|
||||||
// a service account key.
|
|
||||||
defaultValidateServiceAccountKeyTimeout = 5 * time.Second
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config is the configuration for the GCP credential.
|
// Config is the configuration for the GCP credential.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
ProjectId string
|
ProjectId string
|
||||||
PrivateKey string
|
PrivateKey string
|
||||||
PrivateKeyId string
|
PrivateKeyId string
|
||||||
Zone string
|
Zone string
|
||||||
ClientEmail string
|
ClientEmail string
|
||||||
TargetServiceAccountId string
|
TargetServiceAccountId string
|
||||||
Scopes []string
|
Scopes []string
|
||||||
validateServiceAccountKeyTimeout time.Duration
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// credentials represents a simplified version of the GCP credentials file format.
|
// credentials represents a simplified version of the GCP credentials file format.
|
||||||
@@ -76,14 +72,13 @@ func NewConfig(opt ...Option) (*Config, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
c := &Config{
|
c := &Config{
|
||||||
ProjectId: opts.WithProjectId,
|
ProjectId: opts.WithProjectId,
|
||||||
PrivateKey: opts.WithPrivateKey,
|
PrivateKey: opts.WithPrivateKey,
|
||||||
PrivateKeyId: opts.WithPrivateKeyId,
|
PrivateKeyId: opts.WithPrivateKeyId,
|
||||||
ClientEmail: opts.WithClientEmail,
|
ClientEmail: opts.WithClientEmail,
|
||||||
TargetServiceAccountId: opts.WithTargetServiceAccountId,
|
TargetServiceAccountId: opts.WithTargetServiceAccountId,
|
||||||
Zone: opts.WithZone,
|
Zone: opts.WithZone,
|
||||||
Scopes: opts.WithScopes,
|
Scopes: opts.WithScopes,
|
||||||
validateServiceAccountKeyTimeout: defaultValidateServiceAccountKeyTimeout,
|
|
||||||
}
|
}
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
@@ -102,14 +97,13 @@ func (c *Config) toCredentials() *credentials {
|
|||||||
// clone returns a copy of the configuration.
|
// clone returns a copy of the configuration.
|
||||||
func (c *Config) clone() *Config {
|
func (c *Config) clone() *Config {
|
||||||
return &Config{
|
return &Config{
|
||||||
ProjectId: c.ProjectId,
|
ProjectId: c.ProjectId,
|
||||||
Zone: c.Zone,
|
Zone: c.Zone,
|
||||||
PrivateKey: c.PrivateKey,
|
PrivateKey: c.PrivateKey,
|
||||||
PrivateKeyId: c.PrivateKeyId,
|
PrivateKeyId: c.PrivateKeyId,
|
||||||
ClientEmail: c.ClientEmail,
|
ClientEmail: c.ClientEmail,
|
||||||
TargetServiceAccountId: c.TargetServiceAccountId,
|
TargetServiceAccountId: c.TargetServiceAccountId,
|
||||||
Scopes: c.Scopes,
|
Scopes: c.Scopes,
|
||||||
validateServiceAccountKeyTimeout: c.validateServiceAccountKeyTimeout,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -403,14 +403,13 @@ func TestNewConfig(t *testing.T) {
|
|||||||
WithScopes([]string{"scope1", "scope2"}),
|
WithScopes([]string{"scope1", "scope2"}),
|
||||||
},
|
},
|
||||||
expected: &Config{
|
expected: &Config{
|
||||||
ProjectId: "test-project-id",
|
ProjectId: "test-project-id",
|
||||||
PrivateKey: "test-private-key",
|
PrivateKey: "test-private-key",
|
||||||
PrivateKeyId: "test-private-key-id",
|
PrivateKeyId: "test-private-key-id",
|
||||||
ClientEmail: "test-email@example.com",
|
ClientEmail: "test-email@example.com",
|
||||||
TargetServiceAccountId: "target-service-account@example.com",
|
TargetServiceAccountId: "target-service-account@example.com",
|
||||||
Zone: "test-zone",
|
Zone: "test-zone",
|
||||||
Scopes: []string{"scope1", "scope2"},
|
Scopes: []string{"scope1", "scope2"},
|
||||||
validateServiceAccountKeyTimeout: defaultValidateServiceAccountKeyTimeout,
|
|
||||||
},
|
},
|
||||||
expectError: false,
|
expectError: false,
|
||||||
},
|
},
|
||||||
@@ -418,8 +417,7 @@ func TestNewConfig(t *testing.T) {
|
|||||||
name: "No Options",
|
name: "No Options",
|
||||||
options: []Option{},
|
options: []Option{},
|
||||||
expected: &Config{
|
expected: &Config{
|
||||||
Scopes: []string{defaultGCPScope},
|
Scopes: []string{defaultGCPScope},
|
||||||
validateServiceAccountKeyTimeout: defaultValidateServiceAccountKeyTimeout,
|
|
||||||
},
|
},
|
||||||
expectError: false,
|
expectError: false,
|
||||||
},
|
},
|
||||||
@@ -444,14 +442,13 @@ func TestNewConfig(t *testing.T) {
|
|||||||
WithZone("test-zone"),
|
WithZone("test-zone"),
|
||||||
},
|
},
|
||||||
expected: &Config{
|
expected: &Config{
|
||||||
ProjectId: "test-project-id",
|
ProjectId: "test-project-id",
|
||||||
PrivateKey: "test-private-key",
|
PrivateKey: "test-private-key",
|
||||||
PrivateKeyId: "test-private-key-id",
|
PrivateKeyId: "test-private-key-id",
|
||||||
ClientEmail: "test-email@example.com",
|
ClientEmail: "test-email@example.com",
|
||||||
TargetServiceAccountId: "target-service-account@example.com",
|
TargetServiceAccountId: "target-service-account@example.com",
|
||||||
Zone: "test-zone",
|
Zone: "test-zone",
|
||||||
Scopes: []string{defaultGCPScope},
|
Scopes: []string{defaultGCPScope},
|
||||||
validateServiceAccountKeyTimeout: defaultValidateServiceAccountKeyTimeout,
|
|
||||||
},
|
},
|
||||||
expectError: false,
|
expectError: false,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ const (
|
|||||||
// required to delete a service account key.
|
// required to delete a service account key.
|
||||||
// This permission is required to rotate service account keys.
|
// This permission is required to rotate service account keys.
|
||||||
IAMServiceAccountKeysDeletePermission = "iam.serviceAccountKeys.delete"
|
IAMServiceAccountKeysDeletePermission = "iam.serviceAccountKeys.delete"
|
||||||
|
// validateServiceAccountKeyTimeout is the timeout for validating
|
||||||
|
// a service account key.
|
||||||
|
validateServiceAccountKeyTimeout = 5 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
// ServiceAccountPrivateKey represents a decoded PrivateKeyData
|
// ServiceAccountPrivateKey represents a decoded PrivateKeyData
|
||||||
@@ -158,31 +161,19 @@ func (c *Config) ValidateServiceAccountKey(
|
|||||||
var validatePermissionsErr error
|
var validatePermissionsErr error
|
||||||
var validationCallbackErr error
|
var validationCallbackErr error
|
||||||
|
|
||||||
ticker := time.NewTicker(200 * time.Millisecond)
|
for start := time.Now(); time.Since(start) < validateServiceAccountKeyTimeout; time.Sleep(200 * time.Millisecond) {
|
||||||
defer ticker.Stop()
|
_, validatePermissionsErr = c.ValidateIamPermissions(ctx, permissions, opts...)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(ctx, c.validateServiceAccountKeyTimeout)
|
if validateCredsCallback != nil {
|
||||||
defer cancel()
|
validationCallbackErr = validateCredsCallback(c, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
if validatePermissionsErr == nil && validationCallbackErr == nil {
|
||||||
select {
|
return nil
|
||||||
case <-ctx.Done():
|
|
||||||
if ctx.Err() == context.DeadlineExceeded {
|
|
||||||
return fmt.Errorf("failed to validate service account key before timeout: %w", errors.Join(validatePermissionsErr, validationCallbackErr))
|
|
||||||
}
|
|
||||||
return ctx.Err()
|
|
||||||
case <-ticker.C:
|
|
||||||
_, validatePermissionsErr = c.ValidateIamPermissions(ctx, permissions, opts...)
|
|
||||||
|
|
||||||
if validateCredsCallback != nil {
|
|
||||||
validationCallbackErr = validateCredsCallback(c, opts...)
|
|
||||||
}
|
|
||||||
|
|
||||||
if validatePermissionsErr == nil && validationCallbackErr == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return errors.Join(validatePermissionsErr, validationCallbackErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) DeletePrivateKey(ctx context.Context, opts ...option.ClientOption) error {
|
func (c *Config) DeletePrivateKey(ctx context.Context, opts ...option.ClientOption) error {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"cloud.google.com/go/iam/admin/apiv1/adminpb"
|
"cloud.google.com/go/iam/admin/apiv1/adminpb"
|
||||||
"cloud.google.com/go/iam/apiv1/iampb"
|
"cloud.google.com/go/iam/apiv1/iampb"
|
||||||
@@ -31,7 +30,6 @@ func TestRotateServiceAccountKey(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
testValidateTimeout := 1 * time.Second
|
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -78,10 +76,9 @@ func TestRotateServiceAccountKey(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "DeleteServiceAccountKey returns error",
|
name: "DeleteServiceAccountKey returns error",
|
||||||
config: &Config{
|
config: &Config{
|
||||||
PrivateKey: "some-private-key",
|
PrivateKey: "some-private-key",
|
||||||
PrivateKeyId: "some-private-key-id",
|
PrivateKeyId: "some-private-key-id",
|
||||||
ClientEmail: "client@example.com",
|
ClientEmail: "client@example.com",
|
||||||
validateServiceAccountKeyTimeout: testValidateTimeout,
|
|
||||||
},
|
},
|
||||||
setup: func() {
|
setup: func() {
|
||||||
testIAMAdminServer.testCreateServiceAccountKeyError = nil
|
testIAMAdminServer.testCreateServiceAccountKeyError = nil
|
||||||
@@ -92,10 +89,9 @@ func TestRotateServiceAccountKey(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "Successful rotation",
|
name: "Successful rotation",
|
||||||
config: &Config{
|
config: &Config{
|
||||||
PrivateKey: "some-private-key",
|
PrivateKey: "some-private-key",
|
||||||
PrivateKeyId: "some-private-key-id",
|
PrivateKeyId: "some-private-key-id",
|
||||||
ClientEmail: "client@example.com",
|
ClientEmail: "client@example.com",
|
||||||
validateServiceAccountKeyTimeout: testValidateTimeout,
|
|
||||||
},
|
},
|
||||||
setup: func() {
|
setup: func() {
|
||||||
testIAMAdminServer.testCreateServiceAccountKeyError = nil
|
testIAMAdminServer.testCreateServiceAccountKeyError = nil
|
||||||
@@ -265,104 +261,6 @@ func TestValidateIamPermissions(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateServiceAccountKey(t *testing.T) {
|
|
||||||
ctx := context.Background()
|
|
||||||
testResourceServer := &testResourceServer{}
|
|
||||||
testValidateTimeout := 1 * time.Second
|
|
||||||
|
|
||||||
tests := []struct {
|
|
||||||
name string
|
|
||||||
config *Config
|
|
||||||
permissions []string
|
|
||||||
validateCredsCallback ValidateCredsCallback
|
|
||||||
testIamPermissionsError error
|
|
||||||
expectedError error
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "Successful validation",
|
|
||||||
config: &Config{
|
|
||||||
ProjectId: "test-project-id",
|
|
||||||
PrivateKey: "test-private-key",
|
|
||||||
ClientEmail: "test@test.com",
|
|
||||||
validateServiceAccountKeyTimeout: testValidateTimeout,
|
|
||||||
},
|
|
||||||
permissions: []string{
|
|
||||||
ComputeInstancesListPermission,
|
|
||||||
IAMServiceAccountKeysCreatePermission,
|
|
||||||
IAMServiceAccountKeysDeletePermission,
|
|
||||||
},
|
|
||||||
validateCredsCallback: func(c *Config, opts ...googleOption.ClientOption) error {
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
expectedError: nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "Validation callback returns error",
|
|
||||||
config: &Config{
|
|
||||||
ProjectId: "test-project-id",
|
|
||||||
PrivateKey: "test-private-key",
|
|
||||||
ClientEmail: "test@test.com",
|
|
||||||
validateServiceAccountKeyTimeout: testValidateTimeout,
|
|
||||||
},
|
|
||||||
permissions: []string{
|
|
||||||
ComputeInstancesListPermission,
|
|
||||||
IAMServiceAccountKeysCreatePermission,
|
|
||||||
IAMServiceAccountKeysDeletePermission,
|
|
||||||
},
|
|
||||||
validateCredsCallback: func(c *Config, opts ...googleOption.ClientOption) error {
|
|
||||||
return errors.New("validation callback error")
|
|
||||||
},
|
|
||||||
expectedError: errors.New("validation callback error"),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "IAM permissions validation returns error",
|
|
||||||
config: &Config{
|
|
||||||
ProjectId: "test-project-id",
|
|
||||||
PrivateKey: "test-private-key",
|
|
||||||
ClientEmail: "test@test.com",
|
|
||||||
validateServiceAccountKeyTimeout: testValidateTimeout,
|
|
||||||
},
|
|
||||||
permissions: []string{
|
|
||||||
ComputeInstancesListPermission,
|
|
||||||
IAMServiceAccountKeysCreatePermission,
|
|
||||||
IAMServiceAccountKeysDeletePermission,
|
|
||||||
},
|
|
||||||
testIamPermissionsError: errors.New("IAM permissions error"),
|
|
||||||
expectedError: errors.New("failed to validate IAM permissions"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tt := range tests {
|
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
|
||||||
testResourceServer.testIamPermissionsResponse = &iampb.TestIamPermissionsResponse{
|
|
||||||
Permissions: tt.permissions,
|
|
||||||
}
|
|
||||||
testResourceServer.testIamPermissionsError = tt.testIamPermissionsError
|
|
||||||
|
|
||||||
gsrv := NewGRPCServer()
|
|
||||||
resourcemanagerpb.RegisterProjectsServer(gsrv.Server, testResourceServer)
|
|
||||||
addr, err := gsrv.Start()
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
testOptions := []googleOption.ClientOption{
|
|
||||||
googleOption.WithEndpoint(addr),
|
|
||||||
googleOption.WithoutAuthentication(),
|
|
||||||
googleOption.WithGRPCDialOption(grpc.WithTransportCredentials(insecure.NewCredentials())),
|
|
||||||
googleOption.WithTokenSource(nil),
|
|
||||||
}
|
|
||||||
|
|
||||||
err = tt.config.ValidateServiceAccountKey(ctx, tt.permissions, tt.validateCredsCallback, testOptions...)
|
|
||||||
if tt.expectedError != nil {
|
|
||||||
require.ErrorContains(t, err, tt.expectedError.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
require.NoError(t, err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDeletePrivateKey(t *testing.T) {
|
func TestDeletePrivateKey(t *testing.T) {
|
||||||
testIAMAdminServer := &testIAMAdminServer{}
|
testIAMAdminServer := &testIAMAdminServer{}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user