Skip to content

Commit

Permalink
feat: add more documentation and role validation
Browse files Browse the repository at this point in the history
  • Loading branch information
bearaujus committed Dec 23, 2024
1 parent e0642a2 commit 0feebd6
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 19 deletions.
52 changes: 52 additions & 0 deletions plugins/providers/alicloud_ram/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package alicloud_ram

import (
"context"
"errors"
"fmt"
"strings"

Expand Down Expand Up @@ -44,6 +45,23 @@ func NewAliCloudRAMClient(accessKeyID, accessKeySecret, ramRole string) (AliClou
ramRole: ramRole,
}

// Validate the ram role ARN if present
if c.ramRole != "" {
arn, err := parseAliCloudARN(c.ramRole)
if err != nil {
return nil, ErrInvalidAliCloudRoleARN
}
if arn.Service != "ram" {
return nil, ErrRoleServiceTypeIsNotSupported
}
if arn.ResourceType != "role" {
return nil, ErrRoleResourceTypeIsNotSupported
}
if arn.ResourceName == "" {
return nil, ErrRoleResourceNameIsEmpty
}
}

// Validate the configuration by attempting to create a new request client
_, err := c.newRequestClient()
if err != nil {
Expand Down Expand Up @@ -214,3 +232,37 @@ func (c *aliCloudRAMClient) newRequestClient() (*ram.Client, error) {

return reqClient, nil
}

type aliCloudARN struct {
Prefix string // The ARN prefix (e.g., "acs")
Service string // The service name (e.g., "ram")
Region string // The region (empty for global services like RAM)
AccountID string // The account ID (e.g., "5123xxxxxxx")
ResourceType string // The resource type (e.g., "role")
ResourceName string // The resource name (e.g., "role-name")
}

// parseAliCloudARN parses an ARN string into an aliCloudARN struct
// example: `acs:ram::500xxxxxxxx:role/role-name`
func parseAliCloudARN(arn string) (*aliCloudARN, error) {
// Split the ARN string by ":"
parts := strings.Split(arn, ":")
if len(parts) != 5 {
return nil, errors.New("invalid ARN format")
}

// Split the last part to extract resource type and name
resourceParts := strings.Split(parts[4], "/")
if len(resourceParts) != 2 {
return nil, errors.New("invalid resource format")
}

return &aliCloudARN{
Prefix: parts[0],
Service: parts[1],
Region: parts[2],
AccountID: parts[3],
ResourceType: resourceParts[0],
ResourceName: resourceParts[1],
}, nil
}
55 changes: 50 additions & 5 deletions plugins/providers/alicloud_ram/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,34 +13,79 @@ func TestNewAliCloudRAMClient(t *testing.T) {
type args struct {
accessKeyID string
accessKeySecret string
roleToAssume string
ramRole string
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "success creating a new ram user",
name: "error creating AliCloud RAM client with role - invalid role arn",
args: args{
accessKeyID: testAccessKeyID,
accessKeySecret: testAccessKeySecret,
ramRole: "invalid-role-arn",
},
wantErr: true,
},
{
name: "error creating AliCloud RAM client with role - unsupported service type",
args: args{
accessKeyID: testAccessKeyID,
accessKeySecret: testAccessKeySecret,
ramRole: "acs:unsupported-service-type::500xxxxxxxx:role/role-name",
},
wantErr: true,
},
{
name: "error creating AliCloud RAM client with role - invalid resource",
args: args{
accessKeyID: testAccessKeyID,
accessKeySecret: testAccessKeySecret,
ramRole: "acs:ram::500xxxxxxxx:invalid-resource",
},
wantErr: true,
},
{
name: "error creating AliCloud RAM client with role - unsupported resource type",
args: args{
accessKeyID: testAccessKeyID,
accessKeySecret: testAccessKeySecret,
ramRole: "acs:ram::500xxxxxxxx:unsupported-resource-type/role-name",
},
wantErr: true,
},
{
name: "error creating AliCloud RAM client with role - empty role name or resource name",
args: args{
accessKeyID: testAccessKeyID,
accessKeySecret: testAccessKeySecret,
ramRole: "acs:ram::500xxxxxxxx:role/",
},
wantErr: true,
},
{
name: "success creating AliCloud RAM client with role",
args: args{
accessKeyID: testAccessKeyID,
accessKeySecret: testAccessKeySecret,
ramRole: "acs:ram::500xxxxxxxx:role/role-name",
},
wantErr: false,
},
{
name: "success creating a new ram role",
name: "success creating AliCloud RAM client",
args: args{
accessKeyID: testAccessKeyID,
accessKeySecret: testAccessKeySecret,
roleToAssume: "test-role-to-assume",
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
client, err := alicloud_ram.NewAliCloudRAMClient(tt.args.accessKeyID, tt.args.accessKeySecret, tt.args.roleToAssume)
client, err := alicloud_ram.NewAliCloudRAMClient(tt.args.accessKeyID, tt.args.accessKeySecret, tt.args.ramRole)
if tt.wantErr {
assert.Error(t, err)
} else {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 14 additions & 13 deletions plugins/providers/alicloud_ram/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ import (
)

var (
ErrUnimplementedMethod = errors.New("unimplemented method")
ErrUnableToEncryptNilCredentials = errors.New("unable to encrypt nil credentials")
ErrUnableToDecryptNilCredentials = errors.New("unable to decrypt nil credentials")
ErrInvalidCredentials = errors.New("invalid credentials type")
ErrPermissionAlreadyExists = errors.New("permission already exists")
ErrPermissionNotExist = errors.New("permission not exist")
ErrInvalidResourceType = errors.New("invalid resource type")
ErrInvalidAccountType = fmt.Errorf("invalid account type. account type must be one of: %v\n", getAccountTypes())
ErrGrantRoleNotFoundAtResource = errors.New("grant role not found at resource")
ErrEmptyGrantRole = errors.New("empty grant role")
ErrInvalidPolicyType = fmt.Errorf("invalid policy type. policy type must be one of: %v\n", getPolicyTypes())
ErrInvalidAliAccountUserID = errors.New("invalid ali account user id. see: https://github.com/goto/guardian/tree/main/plugins/providers/alicloud_ram/docs/ali-account-user-id-example.png")
ErrEmptyResourceConfig = errors.New("empty resource config")
ErrUnimplementedMethod = errors.New("unimplemented method")
ErrUnableToEncryptNilCredentials = errors.New("unable to encrypt nil credentials")
ErrUnableToDecryptNilCredentials = errors.New("unable to decrypt nil credentials")
ErrInvalidCredentials = errors.New("invalid credentials type")
ErrPermissionAlreadyExists = errors.New("permission already exists")
ErrPermissionNotExist = errors.New("permission not exist")
ErrInvalidResourceType = errors.New("invalid resource type")
ErrInvalidAccountType = fmt.Errorf("invalid account type. account type must be one of: %v\n", getAccountTypes())
ErrInvalidAliCloudAccountUserID = errors.New("invalid account_id for ali account user id. see: https://github.com/goto/guardian/tree/main/plugins/providers/alicloud_ram/docs/ali-account-user-id-example.png")
ErrInvalidAliCloudRoleARN = errors.New("invalid ram_role arn. see: https://github.com/goto/guardian/tree/main/plugins/providers/alicloud_ram/docs/ali-role-arn-example.png")
ErrRoleServiceTypeIsNotSupported = errors.New("ram_role arn only supporting service type 'ram'. see: https://github.com/goto/guardian/tree/main/plugins/providers/alicloud_ram/docs/ali-role-arn-structure.png")
ErrRoleResourceTypeIsNotSupported = errors.New("ram_role arn only supporting resource type 'role'. see: https://github.com/goto/guardian/tree/main/plugins/providers/alicloud_ram/docs/ali-role-arn-structure.png")
ErrRoleResourceNameIsEmpty = errors.New("empty resource name / role name on the ram_role arn. see: https://github.com/goto/guardian/tree/main/plugins/providers/alicloud_ram/docs/ali-role-arn-structure.png")
ErrEmptyResourceConfig = errors.New("empty resource config")
)
2 changes: 1 addition & 1 deletion plugins/providers/alicloud_ram/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ func getResourceTypes() []string {
func splitAliAccountUserId(d string) (string, string, error) {
matched, _ := regexp.MatchString(aliAccountUserIdPattern, d)
if !matched {
return "", "", ErrInvalidAliAccountUserID
return "", "", ErrInvalidAliCloudAccountUserID
}

accountUserIDSplit := strings.Split(d, "@")
Expand Down

0 comments on commit 0feebd6

Please sign in to comment.