From 979e9e981c1f80c4a26099e7b0e896a9d2512e7a Mon Sep 17 00:00:00 2001 From: Ilija Matoski Date: Sun, 15 Jun 2025 21:12:28 +0200 Subject: [PATCH 01/17] move gitlab type to its own package --- gitlab_type.go => internal/gitlab/type.go | 4 ++-- gitlab_type_test.go => internal/gitlab/type_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename gitlab_type.go => internal/gitlab/type.go (89%) rename gitlab_type_test.go => internal/gitlab/type_test.go (93%) diff --git a/gitlab_type.go b/internal/gitlab/type.go similarity index 89% rename from gitlab_type.go rename to internal/gitlab/type.go index c8c998e..22bc7ac 100644 --- a/gitlab_type.go +++ b/internal/gitlab/type.go @@ -18,7 +18,7 @@ const ( var ( ErrUnknownType = errors.New("unknown gitlab type") - validGitlabTypes = []string{ + ValidGitlabTypes = []string{ TypeSaaS.String(), TypeSelfManaged.String(), TypeDedicated.String(), @@ -34,7 +34,7 @@ func (i Type) Value() string { } func TypeParse(value string) (Type, error) { - if slices.Contains(validGitlabTypes, value) { + if slices.Contains(ValidGitlabTypes, value) { return Type(value), nil } return TypeUnknown, fmt.Errorf("failed to parse '%s': %w", value, ErrUnknownType) diff --git a/gitlab_type_test.go b/internal/gitlab/type_test.go similarity index 93% rename from gitlab_type_test.go rename to internal/gitlab/type_test.go index 3dafdad..32df056 100644 --- a/gitlab_type_test.go +++ b/internal/gitlab/type_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" - gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestType(t *testing.T) { From dcfe35f0db5b3582636f57027c0a099cb43c6ff8 Mon Sep 17 00:00:00 2001 From: Ilija Matoski Date: Sun, 15 Jun 2025 21:12:31 +0200 Subject: [PATCH 02/17] move gitlab type to its own package --- entry_config.go | 10 +++++---- entry_config_merge_test.go | 15 ++++++------- entry_config_update_form_field_data_test.go | 7 ++++--- events.go | 2 +- path_config.go | 14 +++++++------ path_config_list_test.go | 13 ++++++------ path_config_rotate.go | 2 +- path_config_test.go | 19 +++++++++-------- path_config_token_autorotate_test.go | 21 ++++++++++--------- path_flags.go | 2 +- path_role.go | 8 ++++--- path_role_deploy_tokens_test.go | 3 ++- ...ole_pipeline_project_trigger_token_test.go | 3 ++- path_role_test.go | 5 +++-- path_role_ttl_test.go | 3 ++- path_token_role.go | 2 +- path_token_role_multiple_config_test.go | 3 ++- path_token_role_test.go | 3 ++- secret_access_tokens.go | 2 +- secret_access_tokens_test.go | 5 +++-- ...dmin_user_pat_gitlab_revokes_token_test.go | 3 ++- ...admin_user_pat_vault_revokes_token_test.go | 3 ++- with_gitlab_com_user_rotate_token_test.go | 3 ++- with_group_deploy_token_test.go | 3 ++- with_normal_user_gat_test.go | 3 ++- with_normal_user_personal_at_fails_test.go | 3 ++- with_normal_user_project_at_test.go | 3 ++- with_pipeline_project_trigger_token_test.go | 3 ++- with_project_deploy_token_test.go | 3 ++- with_service_account_fail_test.go | 7 ++++--- with_service_account_group_test.go | 3 ++- with_service_account_user_test.go | 3 ++- 32 files changed, 106 insertions(+), 76 deletions(-) diff --git a/entry_config.go b/entry_config.go index b9e18e3..0d5b802 100644 --- a/entry_config.go +++ b/entry_config.go @@ -11,6 +11,8 @@ import ( "github.com/hashicorp/go-multierror" "github.com/hashicorp/vault/sdk/framework" "github.com/hashicorp/vault/sdk/logical" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) type EntryConfig struct { @@ -22,7 +24,7 @@ type EntryConfig struct { TokenCreatedAt time.Time `json:"token_created_at" structs:"token_created_at" mapstructure:"token_created_at"` TokenExpiresAt time.Time `json:"token_expires_at" structs:"token_expires_at" mapstructure:"token_expires_at"` Scopes []string `json:"scopes" structs:"scopes" mapstructure:"scopes"` - Type Type `json:"type" structs:"type" mapstructure:"type"` + Type gitlab.Type `json:"type" structs:"type" mapstructure:"type"` Name string `json:"name" structs:"name" mapstructure:"name"` GitlabVersion string `json:"gitlab_version" structs:"gitlab_version" mapstructure:"gitlab_version"` GitlabRevision string `json:"gitlab_revision" structs:"gitlab_revision" mapstructure:"gitlab_revision"` @@ -47,8 +49,8 @@ func (e *EntryConfig) Merge(data *framework.FieldData) (warnings []string, chang } if typ, ok := data.GetOk("type"); ok { - var pType Type - if pType, er = TypeParse(typ.(string)); er != nil { + var pType gitlab.Type + if pType, er = gitlab.TypeParse(typ.(string)); er != nil { err = multierror.Append(err, er) } else { e.Type = pType @@ -115,7 +117,7 @@ func (e *EntryConfig) UpdateFromFieldData(data *framework.FieldData) (warnings [ } if typ, ok := data.GetOk("type"); ok { - if e.Type, er = TypeParse(typ.(string)); er != nil { + if e.Type, er = gitlab.TypeParse(typ.(string)); er != nil { err = multierror.Append(err, er) } } else { diff --git a/entry_config_merge_test.go b/entry_config_merge_test.go index 8c7f32c..e41c562 100644 --- a/entry_config_merge_test.go +++ b/entry_config_merge_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestEntryConfigMerge(t *testing.T) { @@ -46,10 +47,10 @@ func TestEntryConfigMerge(t *testing.T) { }{ { name: "update type only", - originalConfig: &gitlab.EntryConfig{Type: gitlab.TypeSelfManaged}, - expectedConfig: &gitlab.EntryConfig{Type: gitlab.TypeSaaS}, - raw: map[string]interface{}{"type": gitlab.TypeSaaS}, - changes: map[string]string{"type": gitlab.TypeSaaS.String()}, + originalConfig: &gitlab.EntryConfig{Type: gitlab2.TypeSelfManaged}, + expectedConfig: &gitlab.EntryConfig{Type: gitlab2.TypeSaaS}, + raw: map[string]interface{}{"type": gitlab2.TypeSaaS}, + changes: map[string]string{"type": gitlab2.TypeSaaS.String()}, }, { name: "auto rotate token set to false", @@ -67,12 +68,12 @@ func TestEntryConfigMerge(t *testing.T) { }, { name: "update type with invalid type", - originalConfig: &gitlab.EntryConfig{Type: gitlab.TypeSelfManaged}, - expectedConfig: &gitlab.EntryConfig{Type: gitlab.TypeSelfManaged}, + originalConfig: &gitlab.EntryConfig{Type: gitlab2.TypeSelfManaged}, + expectedConfig: &gitlab.EntryConfig{Type: gitlab2.TypeSelfManaged}, raw: map[string]interface{}{"type": "test"}, err: true, errMap: map[string]int{ - gitlab.ErrUnknownType.Error(): 1, + gitlab2.ErrUnknownType.Error(): 1, }, }, { diff --git a/entry_config_update_form_field_data_test.go b/entry_config_update_form_field_data_test.go index 412106c..39ca475 100644 --- a/entry_config_update_form_field_data_test.go +++ b/entry_config_update_form_field_data_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestEntryConfigUpdateFromFieldData(t *testing.T) { @@ -48,7 +49,7 @@ func TestEntryConfigUpdateFromFieldData(t *testing.T) { err: true, errMap: map[string]int{ gitlab.ErrFieldRequired.Error(): 1, - gitlab.ErrUnknownType.Error(): 1, + gitlab2.ErrUnknownType.Error(): 1, }, }, { @@ -64,7 +65,7 @@ func TestEntryConfigUpdateFromFieldData(t *testing.T) { name: "valid config", expectedConfig: &gitlab.EntryConfig{ Token: "token", - Type: gitlab.TypeSelfManaged, + Type: gitlab2.TypeSelfManaged, AutoRotateToken: false, AutoRotateBefore: gitlab.DefaultAutoRotateBeforeMinTTL, BaseURL: "https://gitlab.com", @@ -72,7 +73,7 @@ func TestEntryConfigUpdateFromFieldData(t *testing.T) { warnings: []string{"auto_rotate_token not specified setting to 24h0m0s"}, raw: map[string]interface{}{ "token": "token", - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), "base_url": "https://gitlab.com", }, }, diff --git a/events.go b/events.go index c959c12..a36b5f1 100644 --- a/events.go +++ b/events.go @@ -10,7 +10,7 @@ import ( "google.golang.org/protobuf/types/known/structpb" ) -func event(ctx context.Context, b *framework.Backend, eventType string, metadata map[string]string) { +func Event(ctx context.Context, b *framework.Backend, eventType string, metadata map[string]string) { var err error var ev *logical.EventData if ev, err = logical.NewEvent(); err == nil { diff --git a/path_config.go b/path_config.go index 1750fd9..fd48eb2 100644 --- a/path_config.go +++ b/path_config.go @@ -11,6 +11,8 @@ import ( "github.com/hashicorp/vault/sdk/framework" "github.com/hashicorp/vault/sdk/logical" g "gitlab.com/gitlab-org/api/client-go" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) const ( @@ -40,9 +42,9 @@ var ( Type: framework.TypeString, Required: true, AllowedValues: []any{ - TypeSelfManaged, - TypeSaaS, - TypeDedicated, + gitlab.TypeSelfManaged, + gitlab.TypeSaaS, + gitlab.TypeDedicated, }, Description: `The type of GitLab instance you are connecting to. This could typically distinguish between 'self-managed' for on-premises GitLab installations or 'saas' or 'dedicated' for the GitLab SaaS offering. This field helps the plugin to adjust any necessary configurations or request patterns specific to the type of GitLab instance.`, DisplayAttrs: &framework.DisplayAttributes{ @@ -88,7 +90,7 @@ func (b *Backend) pathConfigDelete(ctx context.Context, req *logical.Request, da } if err = req.Storage.Delete(ctx, fmt.Sprintf("%s/%s", PathConfigStorage, name)); err == nil { - event(ctx, b.Backend, "config-delete", map[string]string{ + Event(ctx, b.Backend, "config-delete", map[string]string{ "path": fmt.Sprintf("%s/%s", PathConfigStorage, name), }) b.SetClient(nil, name) @@ -143,7 +145,7 @@ func (b *Backend) pathConfigPatch(ctx context.Context, req *logical.Request, dat defer b.lockClientMutex.Unlock() if err = saveConfig(ctx, *config, req.Storage); err == nil { lrd := config.LogicalResponseData(b.flags.ShowConfigToken) - event(ctx, b.Backend, "config-patch", changes) + Event(ctx, b.Backend, "config-patch", changes) b.SetClient(nil, name) b.Logger().Debug("Patched config", "lrd", lrd, "warnings", warnings) lResp = &logical.Response{Data: lrd, Warnings: warnings} @@ -202,7 +204,7 @@ func (b *Backend) pathConfigWrite(ctx context.Context, req *logical.Request, dat var lResp *logical.Response if err = saveConfig(ctx, *config, req.Storage); err == nil { - event(ctx, b.Backend, "config-write", map[string]string{ + Event(ctx, b.Backend, "config-write", map[string]string{ "path": fmt.Sprintf("%s/%s", PathConfigStorage, name), "auto_rotate_token": strconv.FormatBool(config.AutoRotateToken), "auto_rotate_before": config.AutoRotateBefore.String(), diff --git a/path_config_list_test.go b/path_config_list_test.go index 9a54598..b25151d 100644 --- a/path_config_list_test.go +++ b/path_config_list_test.go @@ -14,6 +14,7 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestPathConfigList(t *testing.T) { @@ -37,7 +38,7 @@ func TestPathConfigList(t *testing.T) { map[string]any{ "token": getGitlabToken("admin_user_root").Token, "base_url": cmp.Or(os.Getenv("GITLAB_URL"), "http://localhost:8080/"), - "type": gitlab.TypeSaaS.String(), + "type": gitlab2.TypeSaaS.String(), }, gitlab.DefaultConfigName, ) @@ -51,7 +52,7 @@ func TestPathConfigList(t *testing.T) { map[string]any{ "token": getGitlabToken("admin_user_initial_token").Token, "base_url": cmp.Or(os.Getenv("GITLAB_URL"), "http://localhost:8080/"), - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, "admin", ), @@ -62,7 +63,7 @@ func TestPathConfigList(t *testing.T) { map[string]any{ "token": getGitlabToken("normal_user_initial_token").Token, "base_url": cmp.Or(os.Getenv("GITLAB_URL"), "http://localhost:8080/"), - "type": gitlab.TypeDedicated.String(), + "type": gitlab2.TypeDedicated.String(), }, "normal", ), @@ -96,7 +97,7 @@ func TestPathConfigList(t *testing.T) { require.NoError(t, err) require.NotNil(t, resp) require.NotEmpty(t, resp.Data) - require.EqualValues(t, gitlab.TypeSaaS.String(), resp.Data["type"]) + require.EqualValues(t, gitlab2.TypeSaaS.String(), resp.Data["type"]) resp, err = b.HandleRequest(ctx, &logical.Request{ Operation: logical.ReadOperation, @@ -105,7 +106,7 @@ func TestPathConfigList(t *testing.T) { require.NoError(t, err) require.NotNil(t, resp) require.NotEmpty(t, resp.Data) - require.EqualValues(t, gitlab.TypeDedicated.String(), resp.Data["type"]) + require.EqualValues(t, gitlab2.TypeDedicated.String(), resp.Data["type"]) resp, err = b.HandleRequest(ctx, &logical.Request{ Operation: logical.ReadOperation, @@ -114,6 +115,6 @@ func TestPathConfigList(t *testing.T) { require.NoError(t, err) require.NotNil(t, resp) require.NotEmpty(t, resp.Data) - require.EqualValues(t, gitlab.TypeSelfManaged.String(), resp.Data["type"]) + require.EqualValues(t, gitlab2.TypeSelfManaged.String(), resp.Data["type"]) }) } diff --git a/path_config_rotate.go b/path_config_rotate.go index 6663797..47633ea 100644 --- a/path_config_rotate.go +++ b/path_config_rotate.go @@ -103,7 +103,7 @@ func (b *Backend) pathConfigTokenRotate(ctx context.Context, request *logical.Re lResp = &logical.Response{Data: config.LogicalResponseData(b.flags.ShowConfigToken)} lResp.Data["token"] = config.Token - event(ctx, b.Backend, "config-token-rotate", map[string]string{ + Event(ctx, b.Backend, "config-token-rotate", map[string]string{ "path": fmt.Sprintf("%s/%s", PathConfigStorage, name), "expires_at": entryToken.ExpiresAt.Format(time.RFC3339), "created_at": entryToken.CreatedAt.Format(time.RFC3339), diff --git a/path_config_test.go b/path_config_test.go index 5f0ea36..38246be 100644 --- a/path_config_test.go +++ b/path_config_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestPathConfig(t *testing.T) { @@ -58,7 +59,7 @@ func TestPathConfig(t *testing.T) { Data: map[string]any{ "token": getGitlabToken("admin_user_root").Token, "base_url": url, - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) @@ -114,7 +115,7 @@ func TestPathConfig(t *testing.T) { Data: map[string]any{ "token": getGitlabToken("admin_user_root").Token, "base_url": url, - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) @@ -169,7 +170,7 @@ func TestPathConfig(t *testing.T) { Data: map[string]any{ "token": "invalid-token", "base_url": url, - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) @@ -211,7 +212,7 @@ func TestPathConfig(t *testing.T) { Data: map[string]any{ "token": getGitlabToken("admin_user_root").Token, "base_url": url, - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) @@ -232,7 +233,7 @@ func TestPathConfig(t *testing.T) { Data: map[string]any{ "token": getGitlabToken("admin_user_root").Token, "base_url": url, - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) @@ -255,7 +256,7 @@ func TestPathConfig(t *testing.T) { Data: map[string]any{ "token": getGitlabToken("admin_user_root").Token, "base_url": url, - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) @@ -273,14 +274,14 @@ func TestPathConfig(t *testing.T) { require.NoError(t, resp.Error()) tokenOriginalSha1Hash := resp.Data["token_sha1_hash"].(string) require.NotEmpty(t, tokenOriginalSha1Hash) - require.Equal(t, gitlab.TypeSelfManaged.String(), resp.Data["type"]) + require.Equal(t, gitlab2.TypeSelfManaged.String(), resp.Data["type"]) require.NotNil(t, b.GetClient(gitlab.DefaultConfigName).GitlabClient(ctx)) resp, err = b.HandleRequest(ctx, &logical.Request{ Operation: logical.PatchOperation, Path: path, Storage: l, Data: map[string]interface{}{ - "type": gitlab.TypeSaaS.String(), + "type": gitlab2.TypeSaaS.String(), "token": getGitlabToken("admin_user_initial_token").Token, }, }) @@ -291,7 +292,7 @@ func TestPathConfig(t *testing.T) { require.NotEmpty(t, tokenNewSha1Hash) require.NotEqual(t, tokenOriginalSha1Hash, tokenNewSha1Hash) - require.Equal(t, gitlab.TypeSaaS.String(), resp.Data["type"]) + require.Equal(t, gitlab2.TypeSaaS.String(), resp.Data["type"]) require.NotNil(t, b.GetClient(gitlab.DefaultConfigName).GitlabClient(ctx)) events.expectEvents(t, []expectedEvent{ diff --git a/path_config_token_autorotate_test.go b/path_config_token_autorotate_test.go index 231a472..07b7d98 100644 --- a/path_config_token_autorotate_test.go +++ b/path_config_token_autorotate_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestPathConfig_AutoRotate(t *testing.T) { @@ -25,7 +26,7 @@ func TestPathConfig_AutoRotate(t *testing.T) { Data: map[string]any{ "token": getGitlabToken("admin_user_root").Token, "base_url": url, - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) require.NoError(t, err) @@ -44,7 +45,7 @@ func TestPathConfig_AutoRotate(t *testing.T) { "token": getGitlabToken("admin_user_root").Token, "base_url": url, "auto_rotate_before": "2h", - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) require.Error(t, err) @@ -63,7 +64,7 @@ func TestPathConfig_AutoRotate(t *testing.T) { "token": getGitlabToken("admin_user_root").Token, "base_url": url, "auto_rotate_before": (gitlab.DefaultAutoRotateBeforeMaxTTL + time.Hour).String(), - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) require.ErrorIs(t, err, gitlab.ErrInvalidValue) @@ -81,7 +82,7 @@ func TestPathConfig_AutoRotate(t *testing.T) { "token": getGitlabToken("admin_user_root").Token, "base_url": url, "auto_rotate_before": "48h", - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) require.NoError(t, err) @@ -100,7 +101,7 @@ func TestPathConfig_AutoRotate(t *testing.T) { "token": getGitlabToken("admin_user_root").Token, "base_url": url, "auto_rotate_before": (gitlab.DefaultAutoRotateBeforeMinTTL - time.Hour).String(), - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) require.ErrorIs(t, err, gitlab.ErrInvalidValue) @@ -117,7 +118,7 @@ func TestPathConfig_AutoRotate(t *testing.T) { Data: map[string]any{ "token": getGitlabToken("admin_user_root").Token, "base_url": url, - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) require.NoError(t, err) @@ -136,7 +137,7 @@ func TestPathConfig_AutoRotate(t *testing.T) { "token": getGitlabToken("admin_user_root").Token, "base_url": url, "auto_rotate_before": "10h", - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) require.ErrorIs(t, err, gitlab.ErrInvalidValue) @@ -161,7 +162,7 @@ func TestPathConfig_AutoRotateToken(t *testing.T) { b, l, err := getBackendWithConfig(ctx, map[string]any{ "token": "glpat-secret-token", "base_url": url, - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }) require.NoError(t, err) @@ -179,7 +180,7 @@ func TestPathConfig_AutoRotateToken(t *testing.T) { "base_url": url, "auto_rotate_token": true, "auto_rotate_before": "360h", - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }) require.NoError(t, err) @@ -230,7 +231,7 @@ func TestPathConfig_AutoRotateToken(t *testing.T) { "base_url": url, "auto_rotate_token": true, "auto_rotate_before": "24h", - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }) require.NoError(t, err) diff --git a/path_flags.go b/path_flags.go index b9d1f85..ac816a3 100644 --- a/path_flags.go +++ b/path_flags.go @@ -43,7 +43,7 @@ func (b *Backend) pathFlagsUpdate(ctx context.Context, req *logical.Request, dat eventData["show_config_token"] = strconv.FormatBool(b.flags.ShowConfigToken) } - event(ctx, b.Backend, "flags-write", eventData) + Event(ctx, b.Backend, "flags-write", eventData) var flagData map[string]any err = mapstructure.Decode(b.flags, &flagData) diff --git a/path_role.go b/path_role.go index 584b1d8..e5f4df1 100644 --- a/path_role.go +++ b/path_role.go @@ -14,6 +14,8 @@ import ( "github.com/hashicorp/vault/sdk/framework" "github.com/hashicorp/vault/sdk/helper/locksutil" "github.com/hashicorp/vault/sdk/logical" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) const ( @@ -161,7 +163,7 @@ func (b *Backend) pathRolesDelete(ctx context.Context, req *logical.Request, dat return nil, fmt.Errorf("error deleting role: %w", err) } - event(ctx, b.Backend, "role-delete", map[string]string{ + Event(ctx, b.Backend, "role-delete", map[string]string{ "path": "roles", "role_name": roleName, }) @@ -344,7 +346,7 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data err = multierror.Append(err, fmt.Errorf("should be one or more of '%v': %w", validScopes, ErrFieldInvalidValue)) } - if tokenType == TokenTypeUserServiceAccount && (config.Type == TypeSaaS || config.Type == TypeDedicated) { + if tokenType == TokenTypeUserServiceAccount && (config.Type == gitlab.TypeSaaS || config.Type == gitlab.TypeDedicated) { err = multierror.Append(err, fmt.Errorf("cannot create %s with %s: %w", tokenType, config.Type, ErrInvalidValue)) } @@ -365,7 +367,7 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data return nil, err } - event(ctx, b.Backend, "role-write", map[string]string{ + Event(ctx, b.Backend, "role-write", map[string]string{ "path": "roles", "role_name": roleName, "config_name": role.ConfigName, diff --git a/path_role_deploy_tokens_test.go b/path_role_deploy_tokens_test.go index 198ddcc..2029bbf 100644 --- a/path_role_deploy_tokens_test.go +++ b/path_role_deploy_tokens_test.go @@ -15,13 +15,14 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestPathRolesDeployTokens(t *testing.T) { var defaultConfig = map[string]any{ "token": getGitlabToken("admin_user_root").Token, "base_url": cmp.Or(os.Getenv("GITLAB_URL"), "http://localhost:8080/"), - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), } var tests = []struct { diff --git a/path_role_pipeline_project_trigger_token_test.go b/path_role_pipeline_project_trigger_token_test.go index 6728c43..08bd95a 100644 --- a/path_role_pipeline_project_trigger_token_test.go +++ b/path_role_pipeline_project_trigger_token_test.go @@ -15,13 +15,14 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestPathRolesPipelineProjectTrigger(t *testing.T) { var defaultConfig = map[string]any{ "token": getGitlabToken("admin_user_root").Token, "base_url": cmp.Or(os.Getenv("GITLAB_URL"), "http://localhost:8080/"), - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), } t.Run("should fail if have defined scopes or access level", func(t *testing.T) { diff --git a/path_role_test.go b/path_role_test.go index 4d084bd..83a766b 100644 --- a/path_role_test.go +++ b/path_role_test.go @@ -15,6 +15,7 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestPathRolesList(t *testing.T) { @@ -37,7 +38,7 @@ func TestPathRoles(t *testing.T) { var defaultConfig = map[string]any{ "token": getGitlabToken("admin_user_root").Token, "base_url": cmp.Or(os.Getenv("GITLAB_URL"), "http://localhost:8080/"), - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), } t.Run("delete non existing role", func(t *testing.T) { @@ -400,7 +401,7 @@ func TestPathRoles(t *testing.T) { var defaultConfig = map[string]any{ "token": getGitlabToken("admin_user_root").Token, "base_url": cmp.Or(os.Getenv("GITLAB_URL"), "http://localhost:8080/"), - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), } // create a configuration with max ttl set to 10 days diff --git a/path_role_ttl_test.go b/path_role_ttl_test.go index 313a242..2565386 100644 --- a/path_role_ttl_test.go +++ b/path_role_ttl_test.go @@ -14,13 +14,14 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestPathRolesTTL(t *testing.T) { var defaultConfig = map[string]any{ "token": getGitlabToken("admin_user_root").Token, "base_url": cmp.Or(os.Getenv("GITLAB_URL"), "http://localhost:8080/"), - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), } t.Run("general ttl limits", func(t *testing.T) { diff --git a/path_token_role.go b/path_token_role.go index 68b4384..9d82eba 100644 --- a/path_token_role.go +++ b/path_token_role.go @@ -151,7 +151,7 @@ func (b *Backend) pathTokenRoleCreate(ctx context.Context, req *logical.Request, resp.Secret.TTL = token.TTL() } - event( + Event( ctx, b.Backend, "token-write", token.Event(map[string]string{"path": fmt.Sprintf("%s/%s", PathRoleStorage, roleName)}), ) diff --git a/path_token_role_multiple_config_test.go b/path_token_role_multiple_config_test.go index f09a794..6bc4273 100644 --- a/path_token_role_multiple_config_test.go +++ b/path_token_role_multiple_config_test.go @@ -11,6 +11,7 @@ import ( g "gitlab.com/gitlab-org/api/client-go" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestPathTokenRolesMultipleConfigs(t *testing.T) { @@ -35,7 +36,7 @@ func TestPathTokenRolesMultipleConfigs(t *testing.T) { map[string]any{ "token": token, "base_url": gitlabUrl, - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, name, ), diff --git a/path_token_role_test.go b/path_token_role_test.go index 7b9769e..3160e33 100644 --- a/path_token_role_test.go +++ b/path_token_role_test.go @@ -13,13 +13,14 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestPathTokenRoles(t *testing.T) { var defaultConfig = map[string]any{ "token": getGitlabToken("admin_user_root").Token, "base_url": cmp.Or(os.Getenv("GITLAB_URL"), "http://localhost:8080/"), - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), } t.Run("role not found", func(t *testing.T) { diff --git a/secret_access_tokens.go b/secret_access_tokens.go index 2b50a94..503f751 100644 --- a/secret_access_tokens.go +++ b/secret_access_tokens.go @@ -123,7 +123,7 @@ func (b *Backend) secretAccessTokenRevoke(ctx context.Context, req *logical.Requ } } - event(ctx, b.Backend, "token-revoke", map[string]string{ + Event(ctx, b.Backend, "token-revoke", map[string]string{ "lease_id": secret.LeaseID, "path": req.Secret.InternalData["path"].(string), "name": req.Secret.InternalData["name"].(string), diff --git a/secret_access_tokens_test.go b/secret_access_tokens_test.go index d144d06..b854371 100644 --- a/secret_access_tokens_test.go +++ b/secret_access_tokens_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestSecretAccessTokenRevokeToken(t *testing.T) { @@ -38,7 +39,7 @@ func TestSecretAccessTokenRevokeToken(t *testing.T) { "base_url": url, "auto_rotate_token": true, "auto_rotate_before": "24h", - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) @@ -68,7 +69,7 @@ func TestSecretAccessTokenRevokeToken(t *testing.T) { "base_url": url, "auto_rotate_token": true, "auto_rotate_before": "24h", - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) diff --git a/with_admin_user_pat_gitlab_revokes_token_test.go b/with_admin_user_pat_gitlab_revokes_token_test.go index eb19798..32079fc 100644 --- a/with_admin_user_pat_gitlab_revokes_token_test.go +++ b/with_admin_user_pat_gitlab_revokes_token_test.go @@ -15,6 +15,7 @@ import ( g "gitlab.com/gitlab-org/api/client-go" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestWithAdminUser_PAT_AdminUser_GitlabRevokesToken(t *testing.T) { @@ -33,7 +34,7 @@ func TestWithAdminUser_PAT_AdminUser_GitlabRevokesToken(t *testing.T) { "base_url": url, "auto_rotate_token": true, "auto_rotate_before": "24h", - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) diff --git a/with_admin_user_pat_vault_revokes_token_test.go b/with_admin_user_pat_vault_revokes_token_test.go index 187b617..d6046f5 100644 --- a/with_admin_user_pat_vault_revokes_token_test.go +++ b/with_admin_user_pat_vault_revokes_token_test.go @@ -15,6 +15,7 @@ import ( g "gitlab.com/gitlab-org/api/client-go" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestWithAdminUser_PAT_AdminUser_VaultRevokesToken(t *testing.T) { @@ -33,7 +34,7 @@ func TestWithAdminUser_PAT_AdminUser_VaultRevokesToken(t *testing.T) { "base_url": url, "auto_rotate_token": true, "auto_rotate_before": "24h", - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) diff --git a/with_gitlab_com_user_rotate_token_test.go b/with_gitlab_com_user_rotate_token_test.go index cc68d0f..2fc2216 100644 --- a/with_gitlab_com_user_rotate_token_test.go +++ b/with_gitlab_com_user_rotate_token_test.go @@ -12,6 +12,7 @@ import ( g "gitlab.com/gitlab-org/api/client-go" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestWithGitlabUser_RotateToken(t *testing.T) { @@ -31,7 +32,7 @@ func TestWithGitlabUser_RotateToken(t *testing.T) { "base_url": gitlabComUrl, "auto_rotate_token": true, "auto_rotate_before": "24h", - "type": gitlab.TypeSaaS.String(), + "type": gitlab2.TypeSaaS.String(), }, }) diff --git a/with_group_deploy_token_test.go b/with_group_deploy_token_test.go index ab5863d..f76bbd5 100644 --- a/with_group_deploy_token_test.go +++ b/with_group_deploy_token_test.go @@ -13,6 +13,7 @@ import ( g "gitlab.com/gitlab-org/api/client-go" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestWithGroupDeployToken(t *testing.T) { @@ -31,7 +32,7 @@ func TestWithGroupDeployToken(t *testing.T) { "base_url": url, "auto_rotate_token": true, "auto_rotate_before": "24h", - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) diff --git a/with_normal_user_gat_test.go b/with_normal_user_gat_test.go index acbcd83..5c131cb 100644 --- a/with_normal_user_gat_test.go +++ b/with_normal_user_gat_test.go @@ -15,6 +15,7 @@ import ( g "gitlab.com/gitlab-org/api/client-go" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestWithNormalUser_GAT(t *testing.T) { @@ -33,7 +34,7 @@ func TestWithNormalUser_GAT(t *testing.T) { "base_url": url, "auto_rotate_token": true, "auto_rotate_before": "24h", - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) diff --git a/with_normal_user_personal_at_fails_test.go b/with_normal_user_personal_at_fails_test.go index 0ad1a3a..f7d5433 100644 --- a/with_normal_user_personal_at_fails_test.go +++ b/with_normal_user_personal_at_fails_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestWithNormalUser_PersonalAT_Fails(t *testing.T) { @@ -31,7 +32,7 @@ func TestWithNormalUser_PersonalAT_Fails(t *testing.T) { "base_url": url, "auto_rotate_token": true, "auto_rotate_before": "24h", - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) diff --git a/with_normal_user_project_at_test.go b/with_normal_user_project_at_test.go index 52fb5bd..683f5ac 100644 --- a/with_normal_user_project_at_test.go +++ b/with_normal_user_project_at_test.go @@ -15,6 +15,7 @@ import ( g "gitlab.com/gitlab-org/api/client-go" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestWithNormalUser_ProjectAT(t *testing.T) { @@ -33,7 +34,7 @@ func TestWithNormalUser_ProjectAT(t *testing.T) { "base_url": url, "auto_rotate_token": true, "auto_rotate_before": "24h", - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) diff --git a/with_pipeline_project_trigger_token_test.go b/with_pipeline_project_trigger_token_test.go index 60bdf98..16cf515 100644 --- a/with_pipeline_project_trigger_token_test.go +++ b/with_pipeline_project_trigger_token_test.go @@ -12,6 +12,7 @@ import ( g "gitlab.com/gitlab-org/api/client-go" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestWithPipelineProjectTriggerAccessToken(t *testing.T) { @@ -30,7 +31,7 @@ func TestWithPipelineProjectTriggerAccessToken(t *testing.T) { "base_url": url, "auto_rotate_token": true, "auto_rotate_before": "24h", - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) diff --git a/with_project_deploy_token_test.go b/with_project_deploy_token_test.go index 357eddf..41608a5 100644 --- a/with_project_deploy_token_test.go +++ b/with_project_deploy_token_test.go @@ -13,6 +13,7 @@ import ( g "gitlab.com/gitlab-org/api/client-go" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestWithProjectDeployToken(t *testing.T) { @@ -31,7 +32,7 @@ func TestWithProjectDeployToken(t *testing.T) { "base_url": url, "auto_rotate_token": true, "auto_rotate_before": "24h", - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) diff --git a/with_service_account_fail_test.go b/with_service_account_fail_test.go index a4a9fa5..62da413 100644 --- a/with_service_account_fail_test.go +++ b/with_service_account_fail_test.go @@ -11,12 +11,13 @@ import ( g "gitlab.com/gitlab-org/api/client-go" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestWithServiceAccountUserFail(t *testing.T) { - for _, typ := range []gitlab.Type{ - gitlab.TypeSaaS, - gitlab.TypeDedicated, + for _, typ := range []gitlab2.Type{ + gitlab2.TypeSaaS, + gitlab2.TypeDedicated, } { t.Run(typ.String(), func(t *testing.T) { httpClient, _ := getClient(t, "selfhosted") diff --git a/with_service_account_group_test.go b/with_service_account_group_test.go index f4bdc2d..6e99044 100644 --- a/with_service_account_group_test.go +++ b/with_service_account_group_test.go @@ -13,6 +13,7 @@ import ( g "gitlab.com/gitlab-org/api/client-go" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestWithServiceAccountGroup(t *testing.T) { @@ -31,7 +32,7 @@ func TestWithServiceAccountGroup(t *testing.T) { "base_url": gitlabServiceAccountUrl, "auto_rotate_token": true, "auto_rotate_before": "24h", - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) diff --git a/with_service_account_user_test.go b/with_service_account_user_test.go index be515e0..a7fb6cc 100644 --- a/with_service_account_user_test.go +++ b/with_service_account_user_test.go @@ -12,6 +12,7 @@ import ( g "gitlab.com/gitlab-org/api/client-go" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) func TestWithServiceAccountUser(t *testing.T) { @@ -30,7 +31,7 @@ func TestWithServiceAccountUser(t *testing.T) { "base_url": gitlabServiceAccountUrl, "auto_rotate_token": true, "auto_rotate_before": "24h", - "type": gitlab.TypeSelfManaged.String(), + "type": gitlab2.TypeSelfManaged.String(), }, }) From 24a6b2f6d189f13ca7ca2b3bc0fc3ba0db0ab60b Mon Sep 17 00:00:00 2001 From: Ilija Matoski Date: Sun, 15 Jun 2025 21:25:48 +0200 Subject: [PATCH 03/17] move utils and flags --- backend.go | 8 +-- cmd/vault-plugin-secrets-gitlab/main.go | 3 +- defs.go | 9 ---- entry_config.go | 20 ++++---- entry_config_merge_test.go | 7 +-- entry_config_update_form_field_data_test.go | 9 ++-- gitlab_client.go | 19 ++++--- gitlab_client_test.go | 17 ++++--- helpers_test.go | 5 +- internal/errs/errs.go | 11 ++++ flags.go => internal/flags/flags.go | 2 +- flags_test.go => internal/flags/flags_test.go | 4 +- internal/utils/calculate_gitlab_ttl.go | 23 +++++++++ .../utils/calculate_gitlab_ttl_test.go | 34 ++----------- internal/utils/convert_to_int.go | 27 ++++++++++ internal/utils/convert_to_int_test.go | 38 ++++++++++++++ internal/utils/to_any.go | 8 +++ internal/utils/to_any_test.go | 1 + name_tpl.go | 4 +- path_config.go | 9 ++-- path_config_rotate.go | 4 +- path_config_rotate_test.go | 3 +- path_config_test.go | 14 ++--- path_config_token_autorotate_test.go | 9 ++-- path_flags_test.go | 3 +- path_role.go | 28 +++++----- path_role_deploy_tokens_test.go | 3 +- ...ole_pipeline_project_trigger_token_test.go | 3 +- path_role_test.go | 13 ++--- path_role_ttl_test.go | 7 +-- path_token_role.go | 7 ++- secret_access_tokens.go | 9 ++-- secret_access_tokens_test.go | 7 +-- utils.go | 51 ------------------- 34 files changed, 239 insertions(+), 180 deletions(-) create mode 100644 internal/errs/errs.go rename flags.go => internal/flags/flags.go (97%) rename flags_test.go => internal/flags/flags_test.go (84%) create mode 100644 internal/utils/calculate_gitlab_ttl.go rename utils_test.go => internal/utils/calculate_gitlab_ttl_test.go (79%) create mode 100644 internal/utils/convert_to_int.go create mode 100644 internal/utils/convert_to_int_test.go create mode 100644 internal/utils/to_any.go create mode 100644 internal/utils/to_any_test.go delete mode 100644 utils.go diff --git a/backend.go b/backend.go index c1bad21..df5a069 100644 --- a/backend.go +++ b/backend.go @@ -12,6 +12,8 @@ import ( "github.com/hashicorp/vault/sdk/framework" "github.com/hashicorp/vault/sdk/helper/locksutil" "github.com/hashicorp/vault/sdk/logical" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/flags" ) const ( @@ -27,14 +29,14 @@ with the "^config/(?P\w(([\w-.@]+)?\w)?)$" endpoints. ` ) -func Factory(flags Flags) logical.Factory { +func Factory(flags flags.Flags) logical.Factory { return func(ctx context.Context, config *logical.BackendConfig) (logical.Backend, error) { return factory(ctx, config, flags) } } // Factory returns expected new Backend as logical.Backend -func factory(ctx context.Context, conf *logical.BackendConfig, flags Flags) (logical.Backend, error) { +func factory(ctx context.Context, conf *logical.BackendConfig, flags flags.Flags) (logical.Backend, error) { var b = &Backend{ roleLocks: locksutil.CreateLocks(), clients: sync.Map{}, @@ -82,7 +84,7 @@ func factory(ctx context.Context, conf *logical.BackendConfig, flags Flags) (log type Backend struct { *framework.Backend - flags Flags + flags flags.Flags // The client that we can use to create and revoke the access tokens clients sync.Map diff --git a/cmd/vault-plugin-secrets-gitlab/main.go b/cmd/vault-plugin-secrets-gitlab/main.go index c820e71..ff70003 100644 --- a/cmd/vault-plugin-secrets-gitlab/main.go +++ b/cmd/vault-plugin-secrets-gitlab/main.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/vault/sdk/plugin" gat "github.com/ilijamt/vault-plugin-secrets-gitlab" + flags2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/flags" ) var ( @@ -17,7 +18,7 @@ var ( func main() { apiClientMeta := &api.PluginAPIClientMeta{} flags := apiClientMeta.FlagSet() - pf := &gat.Flags{} + pf := &flags2.Flags{} pf.FlagSet(flags) fatalIfError(flags.Parse(os.Args[1:])) diff --git a/defs.go b/defs.go index 61b701a..0aeb2f6 100644 --- a/defs.go +++ b/defs.go @@ -2,19 +2,10 @@ package gitlab import ( "context" - "errors" "net/http" "time" ) -var ( - ErrNilValue = errors.New("nil value") - ErrInvalidValue = errors.New("invalid value") - ErrFieldRequired = errors.New("required field") - ErrFieldInvalidValue = errors.New("invalid value for field") - ErrBackendNotConfigured = errors.New("backend not configured") -) - type contextKey string const ( diff --git a/entry_config.go b/entry_config.go index 0d5b802..2fbe057 100644 --- a/entry_config.go +++ b/entry_config.go @@ -12,7 +12,9 @@ import ( "github.com/hashicorp/vault/sdk/framework" "github.com/hashicorp/vault/sdk/logical" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) type EntryConfig struct { @@ -34,7 +36,7 @@ type EntryConfig struct { func (e *EntryConfig) Merge(data *framework.FieldData) (warnings []string, changes map[string]string, err error) { var er error if data == nil { - return warnings, changes, multierror.Append(fmt.Errorf("data: %w", ErrNilValue)) + return warnings, changes, multierror.Append(fmt.Errorf("data: %w", errs.ErrNilValue)) } if err = data.Validate(); err != nil { @@ -83,11 +85,11 @@ func (e *EntryConfig) Merge(data *framework.FieldData) (warnings []string, chang func (e *EntryConfig) updateAutoRotateBefore(data *framework.FieldData) (warnings []string, err *multierror.Error) { if val, ok := data.GetOk("auto_rotate_before"); ok { - atr, _ := convertToInt(val) + atr, _ := utils.ConvertToInt(val) if atr > int(DefaultAutoRotateBeforeMaxTTL.Seconds()) { - err = multierror.Append(err, fmt.Errorf("auto_rotate_token can not be bigger than %s: %w", DefaultAutoRotateBeforeMaxTTL, ErrInvalidValue)) + err = multierror.Append(err, fmt.Errorf("auto_rotate_token can not be bigger than %s: %w", DefaultAutoRotateBeforeMaxTTL, errs.ErrInvalidValue)) } else if atr <= int(DefaultAutoRotateBeforeMinTTL.Seconds())-1 { - err = multierror.Append(err, fmt.Errorf("auto_rotate_token can not be less than %s: %w", DefaultAutoRotateBeforeMinTTL, ErrInvalidValue)) + err = multierror.Append(err, fmt.Errorf("auto_rotate_token can not be less than %s: %w", DefaultAutoRotateBeforeMinTTL, errs.ErrInvalidValue)) } else { e.AutoRotateBefore = time.Duration(atr) * time.Second } @@ -100,7 +102,7 @@ func (e *EntryConfig) updateAutoRotateBefore(data *framework.FieldData) (warning func (e *EntryConfig) UpdateFromFieldData(data *framework.FieldData) (warnings []string, err error) { if data == nil { - return warnings, multierror.Append(fmt.Errorf("data: %w", ErrNilValue)) + return warnings, multierror.Append(fmt.Errorf("data: %w", errs.ErrNilValue)) } if err = data.Validate(); err != nil { @@ -113,7 +115,7 @@ func (e *EntryConfig) UpdateFromFieldData(data *framework.FieldData) (warnings [ if token, ok := data.GetOk("token"); ok && len(token.(string)) > 0 { e.Token = token.(string) } else { - err = multierror.Append(err, fmt.Errorf("token: %w", ErrFieldRequired)) + err = multierror.Append(err, fmt.Errorf("token: %w", errs.ErrFieldRequired)) } if typ, ok := data.GetOk("type"); ok { @@ -121,13 +123,13 @@ func (e *EntryConfig) UpdateFromFieldData(data *framework.FieldData) (warnings [ err = multierror.Append(err, er) } } else { - err = multierror.Append(err, fmt.Errorf("gitlab type: %w", ErrFieldRequired)) + err = multierror.Append(err, fmt.Errorf("gitlab type: %w", errs.ErrFieldRequired)) } if baseUrl, ok := data.GetOk("base_url"); ok && len(baseUrl.(string)) > 0 { e.BaseURL = baseUrl.(string) } else { - err = multierror.Append(err, fmt.Errorf("base_url: %w", ErrFieldRequired)) + err = multierror.Append(err, fmt.Errorf("base_url: %w", errs.ErrFieldRequired)) } { @@ -175,7 +177,7 @@ func (e *EntryConfig) LogicalResponseData(includeToken bool) (data map[string]an func getConfig(ctx context.Context, s logical.Storage, name string) (cfg *EntryConfig, err error) { if s == nil { - return nil, fmt.Errorf("%w: local.Storage", ErrNilValue) + return nil, fmt.Errorf("%w: local.Storage", errs.ErrNilValue) } var entry *logical.StorageEntry if entry, err = s.Get(ctx, fmt.Sprintf("%s/%s", PathConfigStorage, name)); err == nil { diff --git a/entry_config_merge_test.go b/entry_config_merge_test.go index e41c562..2beee73 100644 --- a/entry_config_merge_test.go +++ b/entry_config_merge_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) @@ -21,7 +22,7 @@ func TestEntryConfigMerge(t *testing.T) { warnings, changes, err := e.Merge(nil) require.Empty(t, warnings) require.Empty(t, changes) - require.ErrorIs(t, err, gitlab.ErrNilValue) + require.ErrorIs(t, err, errs.ErrNilValue) }) t.Run("unconvertible data type", func(t *testing.T) { @@ -96,7 +97,7 @@ func TestEntryConfigMerge(t *testing.T) { expectedConfig: &gitlab.EntryConfig{AutoRotateBefore: gitlab.DefaultAutoRotateBeforeMinTTL + time.Hour}, raw: map[string]interface{}{"auto_rotate_before": "1h"}, err: true, - errMap: map[string]int{gitlab.ErrInvalidValue.Error(): 1}, + errMap: map[string]int{errs.ErrInvalidValue.Error(): 1}, }, { name: "auto rotate before invalid value higher than min", @@ -104,7 +105,7 @@ func TestEntryConfigMerge(t *testing.T) { expectedConfig: &gitlab.EntryConfig{AutoRotateBefore: gitlab.DefaultAutoRotateBeforeMinTTL + time.Hour}, raw: map[string]interface{}{"auto_rotate_before": (gitlab.DefaultAutoRotateBeforeMaxTTL + time.Hour).String()}, err: true, - errMap: map[string]int{gitlab.ErrInvalidValue.Error(): 1}, + errMap: map[string]int{errs.ErrInvalidValue.Error(): 1}, }, { name: "auto rotate with a valid value", diff --git a/entry_config_update_form_field_data_test.go b/entry_config_update_form_field_data_test.go index 39ca475..f617c3b 100644 --- a/entry_config_update_form_field_data_test.go +++ b/entry_config_update_form_field_data_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) @@ -18,7 +19,7 @@ func TestEntryConfigUpdateFromFieldData(t *testing.T) { t.Run("nil data", func(t *testing.T) { e := new(gitlab.EntryConfig) _, err := e.UpdateFromFieldData(nil) - require.ErrorIs(t, err, gitlab.ErrNilValue) + require.ErrorIs(t, err, errs.ErrNilValue) }) var tests = []struct { @@ -35,7 +36,7 @@ func TestEntryConfigUpdateFromFieldData(t *testing.T) { err: true, warnings: []string{"auto_rotate_token not specified setting to 24h0m0s"}, errMap: map[string]int{ - gitlab.ErrFieldRequired.Error(): 3, + errs.ErrFieldRequired.Error(): 3, }, }, { @@ -48,8 +49,8 @@ func TestEntryConfigUpdateFromFieldData(t *testing.T) { warnings: []string{"auto_rotate_token not specified setting to 24h0m0s"}, err: true, errMap: map[string]int{ - gitlab.ErrFieldRequired.Error(): 1, - gitlab2.ErrUnknownType.Error(): 1, + errs.ErrFieldRequired.Error(): 1, + gitlab2.ErrUnknownType.Error(): 1, }, }, { diff --git a/gitlab_client.go b/gitlab_client.go index 55f098a..22ba7be 100644 --- a/gitlab_client.go +++ b/gitlab_client.go @@ -14,6 +14,9 @@ import ( "github.com/hashicorp/vault/sdk/helper/logging" g "gitlab.com/gitlab-org/api/client-go" "golang.org/x/time/rate" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) var ( @@ -214,7 +217,7 @@ func (gc *gitlabClient) GetGroupIdByPath(ctx context.Context, path string) (grou return 0, fmt.Errorf("%v", err) } if len(groups) == 0 { - return 0, fmt.Errorf("path '%s' not found: %w", path, ErrInvalidValue) + return 0, fmt.Errorf("path '%s' not found: %w", path, errs.ErrInvalidValue) } groupId = groups[0].ID return groupId, nil @@ -285,7 +288,7 @@ func (gc *gitlabClient) CreateUserServiceAccountAccessToken(ctx context.Context, func (gc *gitlabClient) RevokeUserServiceAccountAccessToken(ctx context.Context, token string) (err error) { defer func() { gc.logger.Debug("Revoke user service account token", "token", token, "error", err) }() if token == "" { - err = fmt.Errorf("%w: empty token", ErrNilValue) + err = fmt.Errorf("%w: empty token", errs.ErrNilValue) return err } @@ -303,7 +306,7 @@ func (gc *gitlabClient) RevokeUserServiceAccountAccessToken(ctx context.Context, func (gc *gitlabClient) RevokeGroupServiceAccountAccessToken(ctx context.Context, token string) (err error) { defer func() { gc.logger.Debug("Revoke group service account token", "token", token, "error", err) }() if token == "" { - err = fmt.Errorf("%w: empty token", ErrNilValue) + err = fmt.Errorf("%w: empty token", errs.ErrNilValue) return err } @@ -366,7 +369,7 @@ func (gc *gitlabClient) RotateCurrentToken(ctx context.Context) (token *TokenCon var pat *g.PersonalAccessToken var durationTTL = currentEntryToken.ExpiresAt.Sub(*currentEntryToken.CreatedAt) - _, expiresAt, _ = calculateGitlabTTL(durationTTL, TimeFromContext(ctx)) + _, expiresAt, _ = utils.CalculateGitlabTTL(durationTTL, TimeFromContext(ctx)) pat, _, err = gc.client.PersonalAccessTokens.RotatePersonalAccessToken( currentEntryToken.TokenID, &g.RotatePersonalAccessTokenOptions{ExpiresAt: (*g.ISOTime)(&expiresAt)}, @@ -421,7 +424,7 @@ func (gc *gitlabClient) GetUserIdByUsername(ctx context.Context, username string return 0, fmt.Errorf("%v", err) } if len(u) == 0 { - return 0, fmt.Errorf("username '%s' not found: %w", username, ErrInvalidValue) + return 0, fmt.Errorf("username '%s' not found: %w", username, errs.ErrInvalidValue) } userId = u[0].ID return userId, nil @@ -575,11 +578,11 @@ var _ Client = new(gitlabClient) func newGitlabClient(config *EntryConfig, httpClient *http.Client) (gc *g.Client, err error) { if strings.TrimSpace(config.BaseURL) == "" { - err = errors.Join(err, fmt.Errorf("gitlab base url: %w", ErrInvalidValue)) + err = errors.Join(err, fmt.Errorf("gitlab base url: %w", errs.ErrInvalidValue)) } if strings.TrimSpace(config.Token) == "" { - err = errors.Join(err, fmt.Errorf("gitlab token: %w", ErrInvalidValue)) + err = errors.Join(err, fmt.Errorf("gitlab token: %w", errs.ErrInvalidValue)) } if err != nil { @@ -600,7 +603,7 @@ func newGitlabClient(config *EntryConfig, httpClient *http.Client) (gc *g.Client func NewGitlabClient(config *EntryConfig, httpClient *http.Client, logger hclog.Logger) (client Client, err error) { if config == nil { - return nil, fmt.Errorf("configure the backend first, config: %w", ErrNilValue) + return nil, fmt.Errorf("configure the backend first, config: %w", errs.ErrNilValue) } if logger == nil { diff --git a/gitlab_client_test.go b/gitlab_client_test.go index a49ec3c..e63f673 100644 --- a/gitlab_client_test.go +++ b/gitlab_client_test.go @@ -13,24 +13,25 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" ) func TestGitlabClient(t *testing.T) { t.Run("nil config", func(t *testing.T) { client, err := gitlab.NewGitlabClient(nil, nil, nil) require.Nil(t, client) - require.ErrorIs(t, err, gitlab.ErrNilValue) + require.ErrorIs(t, err, errs.ErrNilValue) }) t.Run("no token", func(t *testing.T) { var client, err = gitlab.NewGitlabClient(&gitlab.EntryConfig{}, nil, nil) - require.ErrorIs(t, err, gitlab.ErrInvalidValue) + require.ErrorIs(t, err, errs.ErrInvalidValue) require.Nil(t, client) }) t.Run("no base url", func(t *testing.T) { var client, err = gitlab.NewGitlabClient(&gitlab.EntryConfig{}, nil, nil) - require.ErrorIs(t, err, gitlab.ErrInvalidValue) + require.ErrorIs(t, err, errs.ErrInvalidValue) require.Nil(t, client) }) @@ -51,8 +52,8 @@ func TestGitlabClient(t *testing.T) { }, &http.Client{}, nil) require.NoError(t, err) require.NotNil(t, client) - require.ErrorIs(t, client.RevokeGroupServiceAccountAccessToken(ctx, ""), gitlab.ErrNilValue) - require.ErrorIs(t, client.RevokeUserServiceAccountAccessToken(ctx, ""), gitlab.ErrNilValue) + require.ErrorIs(t, client.RevokeGroupServiceAccountAccessToken(ctx, ""), errs.ErrNilValue) + require.ErrorIs(t, client.RevokeUserServiceAccountAccessToken(ctx, ""), errs.ErrNilValue) }) } @@ -138,7 +139,7 @@ func TestGitlabClient_GetGroupIdByPath(t *testing.T) { require.EqualValues(t, 3, groupId) _, err = client.GetGroupIdByPath(ctx, "nonexistent") - require.ErrorIs(t, err, gitlab.ErrInvalidValue) + require.ErrorIs(t, err, errs.ErrInvalidValue) } func TestGitlabClient_GetUserIdByUsername(t *testing.T) { @@ -173,11 +174,11 @@ func TestGitlabClient_GetUserIdByUsernameDoesNotMatch(t *testing.T) { require.True(t, client.Valid(ctx)) userId, err := client.GetUserIdByUsername(ctx, "ilijamt") - require.ErrorIs(t, err, gitlab.ErrInvalidValue) + require.ErrorIs(t, err, errs.ErrInvalidValue) require.NotEqualValues(t, 1, userId) userId, err = client.GetUserIdByUsername(ctx, "demo") - require.ErrorIs(t, err, gitlab.ErrInvalidValue) + require.ErrorIs(t, err, errs.ErrInvalidValue) require.NotEqualValues(t, 1, userId) } diff --git a/helpers_test.go b/helpers_test.go index 32c26c0..1a4970f 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -27,6 +27,7 @@ import ( g "gitlab.com/gitlab-org/api/client-go" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/flags" ) var _ gitlab.Client = new(inMemoryClient) @@ -93,10 +94,10 @@ func (m *mockEventsSender) expectEvents(t *testing.T, expectedEvents []expectedE } func getBackendWithEvents(ctx context.Context) (*gitlab.Backend, logical.Storage, *mockEventsSender, error) { - return getBackendWithFlagsWithEvents(ctx, gitlab.Flags{}) + return getBackendWithFlagsWithEvents(ctx, flags.Flags{}) } -func getBackendWithFlagsWithEvents(ctx context.Context, flags gitlab.Flags) (*gitlab.Backend, logical.Storage, *mockEventsSender, error) { +func getBackendWithFlagsWithEvents(ctx context.Context, flags flags.Flags) (*gitlab.Backend, logical.Storage, *mockEventsSender, error) { events := &mockEventsSender{} config := &logical.BackendConfig{ Logger: logging.NewVaultLoggerWithWriter(io.Discard, log.NoLevel), diff --git a/internal/errs/errs.go b/internal/errs/errs.go new file mode 100644 index 0000000..be2bbeb --- /dev/null +++ b/internal/errs/errs.go @@ -0,0 +1,11 @@ +package errs + +import "errors" + +var ( + ErrNilValue = errors.New("nil value") + ErrInvalidValue = errors.New("invalid value") + ErrFieldRequired = errors.New("required field") + ErrFieldInvalidValue = errors.New("invalid value for field") + ErrBackendNotConfigured = errors.New("backend not configured") +) diff --git a/flags.go b/internal/flags/flags.go similarity index 97% rename from flags.go rename to internal/flags/flags.go index d2ebb64..82ed05d 100644 --- a/flags.go +++ b/internal/flags/flags.go @@ -1,4 +1,4 @@ -package gitlab +package flags import ( "flag" diff --git a/flags_test.go b/internal/flags/flags_test.go similarity index 84% rename from flags_test.go rename to internal/flags/flags_test.go index b6f3c7f..3a39efb 100644 --- a/flags_test.go +++ b/internal/flags/flags_test.go @@ -1,4 +1,4 @@ -package gitlab_test +package flags_test import ( "flag" @@ -6,7 +6,7 @@ import ( "github.com/stretchr/testify/assert" - gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/flags" ) func TestFlags_FlagSet(t *testing.T) { diff --git a/internal/utils/calculate_gitlab_ttl.go b/internal/utils/calculate_gitlab_ttl.go new file mode 100644 index 0000000..2ef4f1f --- /dev/null +++ b/internal/utils/calculate_gitlab_ttl.go @@ -0,0 +1,23 @@ +package utils + +import ( + "time" +) + +func CalculateGitlabTTL(duration time.Duration, start time.Time) (ttl time.Duration, exp time.Time, err error) { + start = start.UTC() + const D = 24 * time.Hour + const maxDuration = 365 * 24 * time.Hour + if duration > maxDuration { + duration = maxDuration + } + var val = start.Add(duration).Round(0) + exp = val.AddDate(0, 0, 1).Truncate(D) + ttl = exp.Sub(start.Round(0)) + if ttl > maxDuration { + m := start.Add(maxDuration) + exp = time.Date(m.Year(), m.Month(), m.Day(), 0, 0, 0, 0, m.Location()) + ttl = exp.Sub(start.Round(0)) + } + return ttl, exp, nil +} diff --git a/utils_test.go b/internal/utils/calculate_gitlab_ttl_test.go similarity index 79% rename from utils_test.go rename to internal/utils/calculate_gitlab_ttl_test.go index a1c728d..b4cfa59 100644 --- a/utils_test.go +++ b/internal/utils/calculate_gitlab_ttl_test.go @@ -1,6 +1,6 @@ //go:build unit -package gitlab +package utils_test import ( "testing" @@ -8,33 +8,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" -) - -func TestConvertToInt(t *testing.T) { - var tests = []struct { - in any - outVal int - outErr error - }{ - {int(52), int(52), nil}, - {int8(13), int(13), nil}, - {int16(612), int(612), nil}, - {int32(56236), int(56236), nil}, - {int64(23462346), int(23462346), nil}, - {float32(62346.62), int(62346), nil}, - {float64(263467.26), int(263467), nil}, - {"1", int(0), ErrInvalidValue}, - } - for _, tst := range tests { - t.Logf("convertToInt(%T(%v))", tst.in, tst.in) - val, err := convertToInt(tst.in) - assert.Equal(t, tst.outVal, val) - if tst.outErr != nil { - assert.ErrorIs(t, err, tst.outErr) - } - } -} + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" +) func TestCalculateGitlabTTL(t *testing.T) { locMST, err := time.LoadLocation("MST") @@ -118,8 +94,8 @@ func TestCalculateGitlabTTL(t *testing.T) { } for _, tst := range tests { - t.Logf("calculateGitlabTTL(%s, %s) = duration %s, expiry %s, error %v", tst.inDuration, tst.inTime.Format(time.RFC3339), tst.outDuration, tst.outExpiry.Format(time.RFC3339), tst.outErr) - dur, exp, err := calculateGitlabTTL(tst.inDuration, tst.inTime) + t.Logf("CalculateGitlabTTL(%s, %s) = duration %s, expiry %s, error %v", tst.inDuration, tst.inTime.Format(time.RFC3339), tst.outDuration, tst.outExpiry.Format(time.RFC3339), tst.outErr) + dur, exp, err := utils.CalculateGitlabTTL(tst.inDuration, tst.inTime) if err != nil { assert.ErrorIs(t, err, tst.outErr) } diff --git a/internal/utils/convert_to_int.go b/internal/utils/convert_to_int.go new file mode 100644 index 0000000..6bb0ac2 --- /dev/null +++ b/internal/utils/convert_to_int.go @@ -0,0 +1,27 @@ +package utils + +import ( + "fmt" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" +) + +func ConvertToInt(num any) (int, error) { + switch val := num.(type) { + case int: + return val, nil + case int8: + return int(val), nil + case int16: + return int(val), nil + case int32: + return int(val), nil + case int64: + return int(val), nil + case float32: + return int(val), nil + case float64: + return int(val), nil + } + return 0, fmt.Errorf("%v: %w", num, errs.ErrInvalidValue) +} diff --git a/internal/utils/convert_to_int_test.go b/internal/utils/convert_to_int_test.go new file mode 100644 index 0000000..23d554c --- /dev/null +++ b/internal/utils/convert_to_int_test.go @@ -0,0 +1,38 @@ +//go:build unit + +package utils_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" +) + +func TestConvertToInt(t *testing.T) { + var tests = []struct { + in any + outVal int + outErr error + }{ + {int(52), int(52), nil}, + {int8(13), int(13), nil}, + {int16(612), int(612), nil}, + {int32(56236), int(56236), nil}, + {int64(23462346), int(23462346), nil}, + {float32(62346.62), int(62346), nil}, + {float64(263467.26), int(263467), nil}, + {"1", int(0), errs.ErrInvalidValue}, + } + + for _, tst := range tests { + t.Logf("ConvertToInt(%T(%v))", tst.in, tst.in) + val, err := utils.ConvertToInt(tst.in) + assert.Equal(t, tst.outVal, val) + if tst.outErr != nil { + assert.ErrorIs(t, err, tst.outErr) + } + } +} diff --git a/internal/utils/to_any.go b/internal/utils/to_any.go new file mode 100644 index 0000000..98e4af0 --- /dev/null +++ b/internal/utils/to_any.go @@ -0,0 +1,8 @@ +package utils + +func ToAny[T int | string](values ...T) (ret []any) { + for _, value := range values { + ret = append(ret, value) + } + return ret +} diff --git a/internal/utils/to_any_test.go b/internal/utils/to_any_test.go new file mode 100644 index 0000000..90c372d --- /dev/null +++ b/internal/utils/to_any_test.go @@ -0,0 +1 @@ +package utils_test diff --git a/name_tpl.go b/name_tpl.go index 931eb18..9005e56 100644 --- a/name_tpl.go +++ b/name_tpl.go @@ -7,6 +7,8 @@ import ( "text/template" "time" _ "unsafe" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" ) func yesNoBool(in bool) string { @@ -34,7 +36,7 @@ var tplFuncMap = template.FuncMap{ func TokenName(role *EntryRole) (name string, err error) { if role == nil { - return "", fmt.Errorf("role: %w", ErrNilValue) + return "", fmt.Errorf("role: %w", errs.ErrNilValue) } var tpl *template.Template tpl, err = template.New("name").Funcs(tplFuncMap).Parse(role.Name) diff --git a/path_config.go b/path_config.go index fd48eb2..39e1ad4 100644 --- a/path_config.go +++ b/path_config.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/vault/sdk/logical" g "gitlab.com/gitlab-org/api/client-go" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) @@ -86,7 +87,7 @@ func (b *Backend) pathConfigDelete(ctx context.Context, req *logical.Request, da if config, err := getConfig(ctx, req.Storage, name); err == nil { if config == nil { - return logical.ErrorResponse(ErrBackendNotConfigured.Error()), nil + return logical.ErrorResponse(errs.ErrBackendNotConfigured.Error()), nil } if err = req.Storage.Delete(ctx, fmt.Sprintf("%s/%s", PathConfigStorage, name)); err == nil { @@ -108,7 +109,7 @@ func (b *Backend) pathConfigRead(ctx context.Context, req *logical.Request, data var config *EntryConfig if config, err = getConfig(ctx, req.Storage, name); err == nil { if config == nil { - return logical.ErrorResponse(ErrBackendNotConfigured.Error()), nil + return logical.ErrorResponse(errs.ErrBackendNotConfigured.Error()), nil } lrd := config.LogicalResponseData(b.flags.ShowConfigToken) b.Logger().Debug("Reading configuration info", "info", lrd) @@ -127,7 +128,7 @@ func (b *Backend) pathConfigPatch(ctx context.Context, req *logical.Request, dat return nil, err } if config == nil { - return logical.ErrorResponse(ErrBackendNotConfigured.Error()), nil + return logical.ErrorResponse(errs.ErrBackendNotConfigured.Error()), nil } warnings, changes, err = config.Merge(data) @@ -168,7 +169,7 @@ func (b *Backend) updateConfigClientInfo(ctx context.Context, config *EntryConfi et, err = client.CurrentTokenInfo(ctx) if err != nil { - return et, fmt.Errorf("token cannot be validated: %s", ErrInvalidValue) + return et, fmt.Errorf("token cannot be validated: %s", errs.ErrInvalidValue) } config.TokenCreatedAt = *et.CreatedAt diff --git a/path_config_rotate.go b/path_config_rotate.go index 47633ea..2a941b8 100644 --- a/path_config_rotate.go +++ b/path_config_rotate.go @@ -10,6 +10,8 @@ import ( "github.com/hashicorp/vault/sdk/framework" "github.com/hashicorp/vault/sdk/logical" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" ) const pathConfigRotateHelpSynopsis = `Rotate the gitlab token for this configuration.` @@ -70,7 +72,7 @@ func (b *Backend) pathConfigTokenRotate(ctx context.Context, request *logical.Re if config == nil { // no configuration yet so we don't need to rotate anything - return logical.ErrorResponse(ErrBackendNotConfigured.Error()), nil + return logical.ErrorResponse(errs.ErrBackendNotConfigured.Error()), nil } if client, err = b.getClient(ctx, request.Storage, name); err != nil { diff --git a/path_config_rotate_test.go b/path_config_rotate_test.go index 5646dac..d35a8a5 100644 --- a/path_config_rotate_test.go +++ b/path_config_rotate_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" ) func TestPathConfigRotate(t *testing.T) { @@ -24,6 +25,6 @@ func TestPathConfigRotate(t *testing.T) { require.NoError(t, err) require.NotNil(t, resp) require.Error(t, resp.Error()) - require.EqualValues(t, resp.Error(), gitlab.ErrBackendNotConfigured) + require.EqualValues(t, resp.Error(), errs.ErrBackendNotConfigured) }) } diff --git a/path_config_test.go b/path_config_test.go index 38246be..07494fc 100644 --- a/path_config_test.go +++ b/path_config_test.go @@ -12,6 +12,8 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/flags" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) @@ -27,7 +29,7 @@ func TestPathConfig(t *testing.T) { require.NoError(t, err) require.NotNil(t, resp) require.Error(t, resp.Error()) - require.EqualValues(t, resp.Error(), gitlab.ErrBackendNotConfigured) + require.EqualValues(t, resp.Error(), errs.ErrBackendNotConfigured) }) t.Run("deleting uninitialized config should fail with backend not configured", func(t *testing.T) { @@ -43,7 +45,7 @@ func TestPathConfig(t *testing.T) { require.NotNil(t, resp) require.Error(t, resp.Error()) require.True(t, resp.IsError()) - require.EqualValues(t, resp.Error(), gitlab.ErrBackendNotConfigured) + require.EqualValues(t, resp.Error(), errs.ErrBackendNotConfigured) }) t.Run("write, read, delete and read config", func(t *testing.T) { @@ -106,7 +108,7 @@ func TestPathConfig(t *testing.T) { httpClient, url := getClient(t, "unit") ctx := gitlab.HttpClientNewContext(t.Context(), httpClient) - b, l, events, err := getBackendWithFlagsWithEvents(ctx, gitlab.Flags{ShowConfigToken: true}) + b, l, events, err := getBackendWithFlagsWithEvents(ctx, flags.Flags{ShowConfigToken: true}) require.NoError(t, err) resp, err := b.HandleRequest(ctx, &logical.Request{ @@ -195,7 +197,7 @@ func TestPathConfig(t *testing.T) { require.Nil(t, resp) var errorMap = countErrByName(err.(*multierror.Error)) - assert.EqualValues(t, 3, errorMap[gitlab.ErrFieldRequired.Error()]) + assert.EqualValues(t, 3, errorMap[errs.ErrFieldRequired.Error()]) require.Len(t, errorMap, 1) }) @@ -216,7 +218,7 @@ func TestPathConfig(t *testing.T) { }, }) - require.ErrorIs(t, err, gitlab.ErrNilValue) + require.ErrorIs(t, err, errs.ErrNilValue) require.Nil(t, resp) }) @@ -239,7 +241,7 @@ func TestPathConfig(t *testing.T) { require.NoError(t, err) require.NotNil(t, resp) - require.EqualValues(t, resp.Error(), gitlab.ErrBackendNotConfigured) + require.EqualValues(t, resp.Error(), errs.ErrBackendNotConfigured) }) t.Run("patch a config", func(t *testing.T) { diff --git a/path_config_token_autorotate_test.go b/path_config_token_autorotate_test.go index 07b7d98..4534a2e 100644 --- a/path_config_token_autorotate_test.go +++ b/path_config_token_autorotate_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) @@ -50,7 +51,7 @@ func TestPathConfig_AutoRotate(t *testing.T) { }) require.Error(t, err) require.Nil(t, resp) - require.ErrorIs(t, err, gitlab.ErrInvalidValue) + require.ErrorIs(t, err, errs.ErrInvalidValue) }) t.Run("auto_rotate_before should be less than the maximal limit", func(t *testing.T) { @@ -67,7 +68,7 @@ func TestPathConfig_AutoRotate(t *testing.T) { "type": gitlab2.TypeSelfManaged.String(), }, }) - require.ErrorIs(t, err, gitlab.ErrInvalidValue) + require.ErrorIs(t, err, errs.ErrInvalidValue) require.Nil(t, resp) }) @@ -104,7 +105,7 @@ func TestPathConfig_AutoRotate(t *testing.T) { "type": gitlab2.TypeSelfManaged.String(), }, }) - require.ErrorIs(t, err, gitlab.ErrInvalidValue) + require.ErrorIs(t, err, errs.ErrInvalidValue) require.Nil(t, resp) }) @@ -140,7 +141,7 @@ func TestPathConfig_AutoRotate(t *testing.T) { "type": gitlab2.TypeSelfManaged.String(), }, }) - require.ErrorIs(t, err, gitlab.ErrInvalidValue) + require.ErrorIs(t, err, errs.ErrInvalidValue) require.Nil(t, resp) }) } diff --git a/path_flags_test.go b/path_flags_test.go index d68eadc..f5c0b88 100644 --- a/path_flags_test.go +++ b/path_flags_test.go @@ -9,11 +9,12 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/flags" ) func TestPathFlags(t *testing.T) { var ctx = t.Context() - b, l, events, err := getBackendWithFlagsWithEvents(ctx, gitlab.Flags{AllowRuntimeFlagsChange: true}) + b, l, events, err := getBackendWithFlagsWithEvents(ctx, flags.Flags{AllowRuntimeFlagsChange: true}) require.NoError(t, err) resp, err := b.HandleRequest(ctx, &logical.Request{ diff --git a/path_role.go b/path_role.go index e5f4df1..1113b33 100644 --- a/path_role.go +++ b/path_role.go @@ -15,7 +15,9 @@ import ( "github.com/hashicorp/vault/sdk/helper/locksutil" "github.com/hashicorp/vault/sdk/logical" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) const ( @@ -56,7 +58,7 @@ var ( DisplayAttrs: &framework.DisplayAttributes{ Name: "Scopes", }, - AllowedValues: allowedValues(ValidPersonalTokenScopes...), + AllowedValues: utils.ToAny(ValidPersonalTokenScopes...), }, "ttl": { Type: framework.TypeDurationSecond, @@ -73,13 +75,13 @@ var ( DisplayAttrs: &framework.DisplayAttributes{ Name: "Access Level", }, - AllowedValues: allowedValues(ValidAccessLevels...), + AllowedValues: utils.ToAny(ValidAccessLevels...), }, "token_type": { Type: framework.TypeString, Description: "access token type", Required: true, - AllowedValues: allowedValues(validTokenTypes...), + AllowedValues: utils.ToAny(validTokenTypes...), DisplayAttrs: &framework.DisplayAttributes{ Name: "Token Type", }, @@ -213,7 +215,7 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data } if config == nil { - return logical.ErrorResponse(ErrBackendNotConfigured.Error()), nil + return logical.ErrorResponse(errs.ErrBackendNotConfigured.Error()), nil } tokenType, _ = TokenTypeParse(data.Get("token_type").(string)) @@ -238,7 +240,7 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data // validate token type if !slices.Contains(validTokenTypes, tokenType.String()) { - err = multierror.Append(err, fmt.Errorf("token_type='%s', should be one of %v: %w", data.Get("token_type").(string), validTokenTypes, ErrFieldInvalidValue)) + err = multierror.Append(err, fmt.Errorf("token_type='%s', should be one of %v: %w", data.Get("token_type").(string), validTokenTypes, errs.ErrFieldInvalidValue)) } // validate access level and which fields to skip for validation @@ -310,26 +312,26 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data } if required && !ok { - err = multierror.Append(err, fmt.Errorf("%s: %w", name, ErrFieldRequired)) + err = multierror.Append(err, fmt.Errorf("%s: %w", name, errs.ErrFieldRequired)) } else if !required && val == nil { warnings = append(warnings, fmt.Sprintf("field '%s' is using expected default value of %v", name, val)) } if required && name == "ttl" { if role.TTL > DefaultAccessTokenMaxPossibleTTL { - err = multierror.Append(err, fmt.Errorf("ttl = %s [ttl <= max_ttl = %s]: %w", role.TTL.String(), DefaultAccessTokenMaxPossibleTTL, ErrInvalidValue)) + err = multierror.Append(err, fmt.Errorf("ttl = %s [ttl <= max_ttl = %s]: %w", role.TTL.String(), DefaultAccessTokenMaxPossibleTTL, errs.ErrInvalidValue)) } if role.GitlabRevokesTokens && role.TTL < 24*time.Hour { - err = multierror.Append(err, fmt.Errorf("ttl = %s [%s <= ttl <= %s]: %w", role.TTL, DefaultAccessTokenMinTTL, DefaultAccessTokenMaxPossibleTTL, ErrInvalidValue)) + err = multierror.Append(err, fmt.Errorf("ttl = %s [%s <= ttl <= %s]: %w", role.TTL, DefaultAccessTokenMinTTL, DefaultAccessTokenMaxPossibleTTL, errs.ErrInvalidValue)) } if !role.GitlabRevokesTokens && role.TTL < time.Hour { - err = multierror.Append(err, fmt.Errorf("ttl = %s [ttl >= 1h]: %w", role.TTL, ErrInvalidValue)) + err = multierror.Append(err, fmt.Errorf("ttl = %s [ttl >= 1h]: %w", role.TTL, errs.ErrInvalidValue)) } } } if !slices.Contains(validAccessLevels, accessLevel.String()) { - err = multierror.Append(err, fmt.Errorf("access_level='%s', should be one of %v: %w", data.Get("access_level").(string), validAccessLevels, ErrFieldInvalidValue)) + err = multierror.Append(err, fmt.Errorf("access_level='%s', should be one of %v: %w", data.Get("access_level").(string), validAccessLevels, errs.ErrFieldInvalidValue)) } for _, scope := range role.Scopes { @@ -339,15 +341,15 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data } if len(invalidScopes) > 0 { - err = multierror.Append(err, fmt.Errorf("scopes='%v', should be one or more of '%v': %w", invalidScopes, validScopes, ErrFieldInvalidValue)) + err = multierror.Append(err, fmt.Errorf("scopes='%v', should be one or more of '%v': %w", invalidScopes, validScopes, errs.ErrFieldInvalidValue)) } if noEmptyScopes && len(role.Scopes) == 0 { - err = multierror.Append(err, fmt.Errorf("should be one or more of '%v': %w", validScopes, ErrFieldInvalidValue)) + err = multierror.Append(err, fmt.Errorf("should be one or more of '%v': %w", validScopes, errs.ErrFieldInvalidValue)) } if tokenType == TokenTypeUserServiceAccount && (config.Type == gitlab.TypeSaaS || config.Type == gitlab.TypeDedicated) { - err = multierror.Append(err, fmt.Errorf("cannot create %s with %s: %w", tokenType, config.Type, ErrInvalidValue)) + err = multierror.Append(err, fmt.Errorf("cannot create %s with %s: %w", tokenType, config.Type, errs.ErrInvalidValue)) } if err != nil { diff --git a/path_role_deploy_tokens_test.go b/path_role_deploy_tokens_test.go index 2029bbf..bde2e09 100644 --- a/path_role_deploy_tokens_test.go +++ b/path_role_deploy_tokens_test.go @@ -15,6 +15,7 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) @@ -86,7 +87,7 @@ func TestPathRolesDeployTokens(t *testing.T) { require.Error(t, err) require.NotNil(t, resp) var errorMap = countErrByName(err.(*multierror.Error)) - assert.EqualValues(t, 2, errorMap[gitlab.ErrFieldInvalidValue.Error()]) + assert.EqualValues(t, 2, errorMap[errs.ErrFieldInvalidValue.Error()]) }) }) } diff --git a/path_role_pipeline_project_trigger_token_test.go b/path_role_pipeline_project_trigger_token_test.go index 08bd95a..042162b 100644 --- a/path_role_pipeline_project_trigger_token_test.go +++ b/path_role_pipeline_project_trigger_token_test.go @@ -15,6 +15,7 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) @@ -44,7 +45,7 @@ func TestPathRolesPipelineProjectTrigger(t *testing.T) { require.Error(t, err) require.NotNil(t, resp) var errorMap = countErrByName(err.(*multierror.Error)) - assert.EqualValues(t, 2, errorMap[gitlab.ErrFieldInvalidValue.Error()]) + assert.EqualValues(t, 2, errorMap[errs.ErrFieldInvalidValue.Error()]) }) t.Run("ttl is set", func(t *testing.T) { diff --git a/path_role_test.go b/path_role_test.go index 83a766b..800434e 100644 --- a/path_role_test.go +++ b/path_role_test.go @@ -15,6 +15,7 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) @@ -64,7 +65,7 @@ func TestPathRoles(t *testing.T) { require.NoError(t, err) require.NotNil(t, resp) require.Error(t, resp.Error()) - require.EqualValues(t, gitlab.ErrBackendNotConfigured, resp.Error()) + require.EqualValues(t, errs.ErrBackendNotConfigured, resp.Error()) }) t.Run("access level", func(t *testing.T) { @@ -219,8 +220,8 @@ func TestPathRoles(t *testing.T) { require.NotNil(t, resp) require.Error(t, resp.Error()) var errorMap = countErrByName(err.(*multierror.Error)) - assert.EqualValues(t, 4, errorMap[gitlab.ErrFieldRequired.Error()]) - assert.EqualValues(t, 2, errorMap[gitlab.ErrFieldInvalidValue.Error()]) + assert.EqualValues(t, 4, errorMap[errs.ErrFieldRequired.Error()]) + assert.EqualValues(t, 2, errorMap[errs.ErrFieldInvalidValue.Error()]) }) t.Run("invalid name template", func(t *testing.T) { @@ -287,7 +288,7 @@ func TestPathRoles(t *testing.T) { require.Error(t, err) require.NotNil(t, resp) var errorMap = countErrByName(err.(*multierror.Error)) - assert.EqualValues(t, 1, errorMap[gitlab.ErrFieldInvalidValue.Error()]) + assert.EqualValues(t, 1, errorMap[errs.ErrFieldInvalidValue.Error()]) }) }) @@ -331,7 +332,7 @@ func TestPathRoles(t *testing.T) { require.Error(t, err) require.NotNil(t, resp) var errorMap = countErrByName(err.(*multierror.Error)) - assert.EqualValues(t, 1, errorMap[gitlab.ErrFieldInvalidValue.Error()]) + assert.EqualValues(t, 1, errorMap[errs.ErrFieldInvalidValue.Error()]) }) }) @@ -375,7 +376,7 @@ func TestPathRoles(t *testing.T) { require.Error(t, err) require.NotNil(t, resp) var errorMap = countErrByName(err.(*multierror.Error)) - assert.EqualValues(t, 1, errorMap[gitlab.ErrFieldInvalidValue.Error()]) + assert.EqualValues(t, 1, errorMap[errs.ErrFieldInvalidValue.Error()]) }) }) diff --git a/path_role_ttl_test.go b/path_role_ttl_test.go index 2565386..a60aa02 100644 --- a/path_role_ttl_test.go +++ b/path_role_ttl_test.go @@ -14,6 +14,7 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) @@ -50,7 +51,7 @@ func TestPathRolesTTL(t *testing.T) { Data: role, }) require.Error(t, err) - require.ErrorIs(t, err, gitlab.ErrInvalidValue) + require.ErrorIs(t, err, errs.ErrInvalidValue) require.NotNil(t, resp) require.True(t, resp.IsError()) require.ErrorContains(t, resp.Error(), "ttl = 8761h0m0s [ttl <= max_ttl = 8760h0m0s]") @@ -140,7 +141,7 @@ func TestPathRolesTTL(t *testing.T) { Data: role, }) require.Error(t, err) - require.ErrorIs(t, err, gitlab.ErrInvalidValue) + require.ErrorIs(t, err, errs.ErrInvalidValue) require.NotNil(t, resp) require.True(t, resp.IsError()) require.ErrorContains(t, resp.Error(), "ttl = 59m59s [ttl >= 1h]") @@ -173,7 +174,7 @@ func TestPathRolesTTL(t *testing.T) { Data: role, }) require.Error(t, err) - require.ErrorIs(t, err, gitlab.ErrInvalidValue) + require.ErrorIs(t, err, errs.ErrInvalidValue) require.NotNil(t, resp) require.True(t, resp.IsError()) require.ErrorContains(t, resp.Error(), "ttl = 23h59m59s [24h0m0s <= ttl <= 8760h0m0s]") diff --git a/path_token_role.go b/path_token_role.go index 9d82eba..ed1042f 100644 --- a/path_token_role.go +++ b/path_token_role.go @@ -11,6 +11,9 @@ import ( "github.com/hashicorp/vault/sdk/framework" "github.com/hashicorp/vault/sdk/helper/locksutil" "github.com/hashicorp/vault/sdk/logical" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) const ( @@ -69,7 +72,7 @@ func (b *Backend) pathTokenRoleCreate(ctx context.Context, req *logical.Request, var gitlabRevokesTokens = role.GitlabRevokesTokens var vaultRevokesTokens = !role.GitlabRevokesTokens - _, expiresAt, _ = calculateGitlabTTL(role.TTL, startTime) + _, expiresAt, _ = utils.CalculateGitlabTTL(role.TTL, startTime) client, err = b.getClient(ctx, req.Storage, role.ConfigName) if err != nil { @@ -128,7 +131,7 @@ func (b *Backend) pathTokenRoleCreate(ctx context.Context, req *logical.Request, } if err != nil || token == nil { - return nil, cmp.Or(err, fmt.Errorf("%w: token is nil", ErrNilValue)) + return nil, cmp.Or(err, fmt.Errorf("%w: token is nil", errs.ErrNilValue)) } token.SetConfigName(cmp.Or(role.ConfigName, DefaultConfigName)) diff --git a/secret_access_tokens.go b/secret_access_tokens.go index 503f751..edb66ea 100644 --- a/secret_access_tokens.go +++ b/secret_access_tokens.go @@ -8,6 +8,9 @@ import ( "github.com/hashicorp/vault/sdk/framework" "github.com/hashicorp/vault/sdk/logical" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) const ( @@ -55,12 +58,12 @@ func (b *Backend) secretAccessTokenRevoke(ctx context.Context, req *logical.Requ var err error if req.Storage == nil { - return nil, fmt.Errorf("storage: %w", ErrNilValue) + return nil, fmt.Errorf("storage: %w", errs.ErrNilValue) } var secret = req.Secret if secret == nil { - return nil, fmt.Errorf("secret: %w", ErrNilValue) + return nil, fmt.Errorf("secret: %w", errs.ErrNilValue) } var configName = DefaultConfigName @@ -69,7 +72,7 @@ func (b *Backend) secretAccessTokenRevoke(ctx context.Context, req *logical.Requ } var tokenId int - tokenId, err = convertToInt(req.Secret.InternalData["token_id"]) + tokenId, err = utils.ConvertToInt(req.Secret.InternalData["token_id"]) if err != nil { return nil, fmt.Errorf("token_id: %w", err) } diff --git a/secret_access_tokens_test.go b/secret_access_tokens_test.go index b854371..311095e 100644 --- a/secret_access_tokens_test.go +++ b/secret_access_tokens_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) @@ -25,7 +26,7 @@ func TestSecretAccessTokenRevokeToken(t *testing.T) { resp, err := b.Secret(gitlab.SecretAccessTokenType).HandleRevoke(ctx, &logical.Request{}) require.Error(t, err) require.Nil(t, resp) - require.ErrorIs(t, err, gitlab.ErrNilValue) + require.ErrorIs(t, err, errs.ErrNilValue) events.expectEvents(t, []expectedEvent{}) }) @@ -51,7 +52,7 @@ func TestSecretAccessTokenRevokeToken(t *testing.T) { resp, err = b.Secret(gitlab.SecretAccessTokenType).HandleRevoke(ctx, &logical.Request{Storage: l}) require.Error(t, err) require.Nil(t, resp) - require.ErrorIs(t, err, gitlab.ErrNilValue) + require.ErrorIs(t, err, errs.ErrNilValue) events.expectEvents(t, []expectedEvent{ {eventType: "gitlab/config-write"}, @@ -88,7 +89,7 @@ func TestSecretAccessTokenRevokeToken(t *testing.T) { }) require.Error(t, err) require.Nil(t, resp) - require.ErrorIs(t, err, gitlab.ErrInvalidValue) + require.ErrorIs(t, err, errs.ErrInvalidValue) events.expectEvents(t, []expectedEvent{ {eventType: "gitlab/config-write"}, diff --git a/utils.go b/utils.go deleted file mode 100644 index 6303bf7..0000000 --- a/utils.go +++ /dev/null @@ -1,51 +0,0 @@ -package gitlab - -import ( - "fmt" - "time" -) - -func allowedValues(values ...string) (ret []any) { - for _, value := range values { - ret = append(ret, value) - } - return ret -} - -func convertToInt(num any) (int, error) { - switch val := num.(type) { - case int: - return val, nil - case int8: - return int(val), nil - case int16: - return int(val), nil - case int32: - return int(val), nil - case int64: - return int(val), nil - case float32: - return int(val), nil - case float64: - return int(val), nil - } - return 0, fmt.Errorf("%v: %w", num, ErrInvalidValue) -} - -func calculateGitlabTTL(duration time.Duration, start time.Time) (ttl time.Duration, exp time.Time, err error) { - start = start.UTC() - const D = 24 * time.Hour - const maxDuration = 365 * 24 * time.Hour - if duration > maxDuration { - duration = maxDuration - } - var val = start.Add(duration).Round(0) - exp = val.AddDate(0, 0, 1).Truncate(D) - ttl = exp.Sub(start.Round(0)) - if ttl > maxDuration { - m := start.Add(maxDuration) - exp = time.Date(m.Year(), m.Month(), m.Day(), 0, 0, 0, 0, m.Location()) - ttl = exp.Sub(start.Round(0)) - } - return ttl, exp, nil -} From f54fed9d512dea80c2007a14282a8d3ca18ebf11 Mon Sep 17 00:00:00 2001 From: Ilija Matoski Date: Sun, 15 Jun 2025 21:38:08 +0200 Subject: [PATCH 04/17] cleanup and add some go docs --- cmd/vault-plugin-secrets-gitlab/main.go | 4 +- internal/errs/errs.go | 17 +++++-- internal/flags/flags.go | 9 +++- internal/gitlab/type.go | 25 +++++++--- internal/utils/to_any.go | 1 + internal/utils/to_any_test.go | 61 +++++++++++++++++++++++++ 6 files changed, 102 insertions(+), 15 deletions(-) diff --git a/cmd/vault-plugin-secrets-gitlab/main.go b/cmd/vault-plugin-secrets-gitlab/main.go index ff70003..186713a 100644 --- a/cmd/vault-plugin-secrets-gitlab/main.go +++ b/cmd/vault-plugin-secrets-gitlab/main.go @@ -8,7 +8,7 @@ import ( "github.com/hashicorp/vault/sdk/plugin" gat "github.com/ilijamt/vault-plugin-secrets-gitlab" - flags2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/flags" + f "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/flags" ) var ( @@ -18,7 +18,7 @@ var ( func main() { apiClientMeta := &api.PluginAPIClientMeta{} flags := apiClientMeta.FlagSet() - pf := &flags2.Flags{} + pf := &f.Flags{} pf.FlagSet(flags) fatalIfError(flags.Parse(os.Args[1:])) diff --git a/internal/errs/errs.go b/internal/errs/errs.go index be2bbeb..ccb4f41 100644 --- a/internal/errs/errs.go +++ b/internal/errs/errs.go @@ -3,9 +3,18 @@ package errs import "errors" var ( - ErrNilValue = errors.New("nil value") - ErrInvalidValue = errors.New("invalid value") - ErrFieldRequired = errors.New("required field") - ErrFieldInvalidValue = errors.New("invalid value for field") + // ErrNilValue represents an error indicating a nil value was encountered where it is not allowed. + ErrNilValue = errors.New("nil value") + + // ErrInvalidValue indicates that an operation encountered a value that is considered invalid or inappropriate. + ErrInvalidValue = errors.New("invalid value") + + // ErrFieldRequired represents an error when a required field is missing + ErrFieldRequired = errors.New("required field") + + // ErrFieldInvalidValue represents an error when a field contains an invalid value + ErrFieldInvalidValue = errors.New("invalid value for field") + + // ErrBackendNotConfigured represents an error when trying to use a backend that hasn't been properly configured ErrBackendNotConfigured = errors.New("backend not configured") ) diff --git a/internal/flags/flags.go b/internal/flags/flags.go index 82ed05d..9f08eb0 100644 --- a/internal/flags/flags.go +++ b/internal/flags/flags.go @@ -4,12 +4,17 @@ import ( "flag" ) +// Flags represent a set of configurable options affecting runtime behavior and configuration visibility. type Flags struct { - ShowConfigToken bool `json:"show_config_token" mapstructure:"show_config_token"` + + // ShowConfigToken determines if the configuration token value should be displayed when accessing the configuration endpoint. + ShowConfigToken bool `json:"show_config_token" mapstructure:"show_config_token"` + + // AllowRuntimeFlagsChange determines whether runtime flags can be dynamically modified during execution. AllowRuntimeFlagsChange bool `json:"allow_runtime_flags_change" mapstructure:"allow_runtime_flags_change"` } -// FlagSet returns the flag set for configuring the TLS connection +// FlagSet configures the provided FlagSet with flags managed by the Flags struct and returns the updated FlagSet. func (f *Flags) FlagSet(fs *flag.FlagSet) *flag.FlagSet { fs.BoolVar(&f.ShowConfigToken, "show-config-token", false, "Display the token value when reading it's config the configuration endpoint.") fs.BoolVar(&f.AllowRuntimeFlagsChange, "allow-runtime-flags-change", false, "Allows you to change the flags dynamically at runtime.") diff --git a/internal/gitlab/type.go b/internal/gitlab/type.go index 22bc7ac..4de8f09 100644 --- a/internal/gitlab/type.go +++ b/internal/gitlab/type.go @@ -1,40 +1,51 @@ package gitlab import ( - "errors" "fmt" "slices" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" ) +// Type defines a string-based type to represent specific categories or modes, such as "saas" or "self-managed". This is the Gitlab Type type Type string const ( - TypeSaaS Type = "saas" - TypeDedicated Type = "dedicated" + // TypeSaaS represents the "saas" type, indicating the software-as-a-service mode for GitLab deployments. + TypeSaaS Type = "saas" + // TypeDedicated represents the "dedicated" type, indicating a dedicated mode for GitLab deployments. + TypeDedicated Type = "dedicated" + // TypeSelfManaged represents the "self-managed" type, indicating a self-hosted mode for GitLab deployments. TypeSelfManaged Type = "self-managed" - TypeUnknown = Type("") + + // TypeUnknown represents an uninitialized or unknown GitLab deployment type, used as a default fallback value. + TypeUnknown = Type("") ) var ( - ErrUnknownType = errors.New("unknown gitlab type") + ErrUnknownType = fmt.Errorf("%s: gitlab type", errs.ErrInvalidValue) - ValidGitlabTypes = []string{ + validGitlabTypes = []string{ TypeSaaS.String(), TypeSelfManaged.String(), TypeDedicated.String(), } ) +// String converts the Type value to its underlying string representation. func (i Type) String() string { return string(i) } +// Value returns the string representation of the Type by invoking the String method. func (i Type) Value() string { return i.String() } +// TypeParse attempts to parse the given string into a valid GitLab Type. +// Returns the corresponding Type and nil error if successful, or TypeUnknown and an error if parsing fails. func TypeParse(value string) (Type, error) { - if slices.Contains(ValidGitlabTypes, value) { + if slices.Contains(validGitlabTypes, value) { return Type(value), nil } return TypeUnknown, fmt.Errorf("failed to parse '%s': %w", value, ErrUnknownType) diff --git a/internal/utils/to_any.go b/internal/utils/to_any.go index 98e4af0..b97ed63 100644 --- a/internal/utils/to_any.go +++ b/internal/utils/to_any.go @@ -1,6 +1,7 @@ package utils func ToAny[T int | string](values ...T) (ret []any) { + ret = make([]any, 0, len(values)) for _, value := range values { ret = append(ret, value) } diff --git a/internal/utils/to_any_test.go b/internal/utils/to_any_test.go index 90c372d..d8b115f 100644 --- a/internal/utils/to_any_test.go +++ b/internal/utils/to_any_test.go @@ -1 +1,62 @@ package utils_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" +) + +func TestToAny(t *testing.T) { + tests := []struct { + name string + input any + expected []any + }{ + { + name: "empty int slice", + input: []int{}, + expected: []any{}, + }, + { + name: "single int", + input: []int{42}, + expected: []any{42}, + }, + { + name: "multiple ints", + input: []int{1, 2, 3}, + expected: []any{1, 2, 3}, + }, + { + name: "empty string slice", + input: []string{}, + expected: []any{}, + }, + { + name: "single string", + input: []string{"hello"}, + expected: []any{"hello"}, + }, + { + name: "multiple strings", + input: []string{"a", "b", "c"}, + expected: []any{"a", "b", "c"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var result []any + switch v := tt.input.(type) { + case []int: + result = utils.ToAny(v...) + case []string: + result = utils.ToAny(v...) + } + + assert.EqualValues(t, tt.expected, result) + }) + } +} From 5a15c588e7c94f9d5585d222638272d45605375d Mon Sep 17 00:00:00 2001 From: Ilija Matoski Date: Mon, 16 Jun 2025 17:35:24 +0200 Subject: [PATCH 05/17] move token type to internal/token pkg --- entry_role.go | 20 ++++---- gitlab_client.go | 21 ++++---- gitlab_client_test.go | 9 ++-- helpers_test.go | 49 ++++++++++--------- type_token_type.go => internal/token/type.go | 6 +-- .../token/type_test.go | 4 +- name_tpl_rand_string_test.go | 3 +- name_tpl_test.go | 9 ++-- name_tpl_unix_timestamp_test.go | 3 +- path_role.go | 33 +++++++------ path_role_deploy_tokens_test.go | 7 +-- ...ole_pipeline_project_trigger_token_test.go | 7 +-- path_role_test.go | 47 +++++++++--------- path_role_ttl_test.go | 7 +-- path_token_role.go | 19 +++---- path_token_role_multiple_config_test.go | 17 ++++--- path_token_role_test.go | 27 +++++----- secret_access_tokens.go | 21 ++++---- token.go | 28 ++++++----- ...dmin_user_pat_gitlab_revokes_token_test.go | 5 +- ...admin_user_pat_vault_revokes_token_test.go | 5 +- with_group_deploy_token_test.go | 5 +- with_normal_user_gat_test.go | 3 +- with_normal_user_personal_at_fails_test.go | 5 +- with_normal_user_project_at_test.go | 5 +- with_pipeline_project_trigger_token_test.go | 5 +- with_project_deploy_token_test.go | 5 +- with_service_account_fail_test.go | 3 +- with_service_account_group_test.go | 3 +- with_service_account_user_test.go | 3 +- 30 files changed, 207 insertions(+), 177 deletions(-) rename type_token_type.go => internal/token/type.go (93%) rename type_token_type_test.go => internal/token/type_test.go (94%) diff --git a/entry_role.go b/entry_role.go index a5b086e..aedfd45 100644 --- a/entry_role.go +++ b/entry_role.go @@ -6,18 +6,20 @@ import ( "time" "github.com/hashicorp/vault/sdk/logical" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) type EntryRole struct { - RoleName string `json:"role_name" structs:"role_name" mapstructure:"role_name"` - TTL time.Duration `json:"ttl" structs:"ttl" mapstructure:"ttl"` - Path string `json:"path" structs:"path" mapstructure:"path"` - Name string `json:"name" structs:"name" mapstructure:"name"` - Scopes []string `json:"scopes" structs:"scopes" mapstructure:"scopes"` - AccessLevel AccessLevel `json:"access_level" structs:"access_level" mapstructure:"access_level,omitempty"` - TokenType TokenType `json:"token_type" structs:"token_type" mapstructure:"token_type"` - GitlabRevokesTokens bool `json:"gitlab_revokes_token" structs:"gitlab_revokes_token" mapstructure:"gitlab_revokes_token"` - ConfigName string `json:"config_name" structs:"config_name" mapstructure:"config_name"` + RoleName string `json:"role_name" structs:"role_name" mapstructure:"role_name"` + TTL time.Duration `json:"ttl" structs:"ttl" mapstructure:"ttl"` + Path string `json:"path" structs:"path" mapstructure:"path"` + Name string `json:"name" structs:"name" mapstructure:"name"` + Scopes []string `json:"scopes" structs:"scopes" mapstructure:"scopes"` + AccessLevel AccessLevel `json:"access_level" structs:"access_level" mapstructure:"access_level,omitempty"` + TokenType token.TokenType `json:"token_type" structs:"token_type" mapstructure:"token_type"` + GitlabRevokesTokens bool `json:"gitlab_revokes_token" structs:"gitlab_revokes_token" mapstructure:"gitlab_revokes_token"` + ConfigName string `json:"config_name" structs:"config_name" mapstructure:"config_name"` } func (e EntryRole) LogicalResponseData() map[string]any { diff --git a/gitlab_client.go b/gitlab_client.go index 22ba7be..e3d402e 100644 --- a/gitlab_client.go +++ b/gitlab_client.go @@ -16,6 +16,7 @@ import ( "golang.org/x/time/rate" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" + t "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) @@ -95,7 +96,7 @@ func (gc *gitlabClient) CreateGroupDeployToken(ctx context.Context, path string, Path: path, Name: name, Token: dt.Token, - TokenType: TokenTypeGroupDeploy, + TokenType: t.TokenTypeGroupDeploy, CreatedAt: g.Ptr(time.Now()), }, Scopes: scopes, @@ -128,7 +129,7 @@ func (gc *gitlabClient) CreateProjectDeployToken(ctx context.Context, path strin Path: path, Name: name, Token: dt.Token, - TokenType: TokenTypeProjectDeploy, + TokenType: t.TokenTypeProjectDeploy, CreatedAt: g.Ptr(time.Now()), }, Scopes: scopes, @@ -184,7 +185,7 @@ func (gc *gitlabClient) CreatePipelineProjectTriggerAccessToken(ctx context.Cont Path: path, Name: name, Token: pt.Token, - TokenType: TokenTypePipelineProjectTrigger, + TokenType: t.TokenTypePipelineProjectTrigger, CreatedAt: g.Ptr(time.Now()), ExpiresAt: expiresAt, }, @@ -247,7 +248,7 @@ func (gc *gitlabClient) CreateGroupServiceAccountAccessToken(ctx context.Context Path: path, Name: name, Token: at.Token, - TokenType: TokenTypeGroupServiceAccount, + TokenType: t.TokenTypeGroupServiceAccount, CreatedAt: at.CreatedAt, ExpiresAt: (*time.Time)(at.ExpiresAt), }, @@ -274,7 +275,7 @@ func (gc *gitlabClient) CreateUserServiceAccountAccessToken(ctx context.Context, Path: etp.Path, Name: etp.Name, Token: etp.Token.Token, - TokenType: TokenTypeUserServiceAccount, + TokenType: t.TokenTypeUserServiceAccount, CreatedAt: etp.CreatedAt, ExpiresAt: etp.ExpiresAt, }, @@ -331,7 +332,7 @@ func (gc *gitlabClient) CurrentTokenInfo(ctx context.Context) (et *TokenConfig, TokenID: pat.ID, Name: pat.Name, Token: pat.Token, - TokenType: TokenTypePersonal, + TokenType: t.TokenTypePersonal, CreatedAt: pat.CreatedAt, ExpiresAt: (*time.Time)(pat.ExpiresAt), }, @@ -387,7 +388,7 @@ func (gc *gitlabClient) RotateCurrentToken(ctx context.Context) (token *TokenCon Path: usr.Username, Name: pat.Name, Token: pat.Token, - TokenType: TokenTypePersonal, + TokenType: t.TokenTypePersonal, CreatedAt: pat.CreatedAt, ExpiresAt: (*time.Time)(pat.ExpiresAt), }, @@ -447,7 +448,7 @@ func (gc *gitlabClient) CreatePersonalAccessToken(ctx context.Context, username Path: username, Name: name, Token: at.Token, - TokenType: TokenTypePersonal, + TokenType: t.TokenTypePersonal, CreatedAt: at.CreatedAt, ExpiresAt: (*time.Time)(at.ExpiresAt), }, @@ -480,7 +481,7 @@ func (gc *gitlabClient) CreateGroupAccessToken(ctx context.Context, groupId stri Path: groupId, Name: name, Token: at.Token, - TokenType: TokenTypeGroup, + TokenType: t.TokenTypeGroup, CreatedAt: at.CreatedAt, ExpiresAt: (*time.Time)(at.ExpiresAt), }, @@ -513,7 +514,7 @@ func (gc *gitlabClient) CreateProjectAccessToken(ctx context.Context, projectId Path: projectId, Name: name, Token: at.Token, - TokenType: TokenTypeProject, + TokenType: t.TokenTypeProject, CreatedAt: at.CreatedAt, ExpiresAt: (*time.Time)(at.ExpiresAt), }, diff --git a/gitlab_client_test.go b/gitlab_client_test.go index e63f673..a210c89 100644 --- a/gitlab_client_test.go +++ b/gitlab_client_test.go @@ -14,6 +14,7 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" + token2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestGitlabClient(t *testing.T) { @@ -216,7 +217,7 @@ func TestGitlabClient_CurrentTokenInfo(t *testing.T) { token, err := client.CurrentTokenInfo(ctx) require.NoError(t, err) require.NotNil(t, token) - assert.EqualValues(t, gitlab.TokenTypePersonal, token.TokenType) + assert.EqualValues(t, token2.TokenTypePersonal, token.TokenType) } func TestGitlabClient_Metadata(t *testing.T) { @@ -261,7 +262,7 @@ func TestGitlabClient_CreateAccessToken_And_Revoke(t *testing.T) { ) require.NoError(t, err) require.NotNil(t, gatToken) - require.EqualValues(t, gitlab.TokenTypeGroup, gatToken.TokenType) + require.EqualValues(t, token2.TokenTypeGroup, gatToken.TokenType) require.NotEmpty(t, gatToken.Token) require.NoError(t, client.RevokeGroupAccessToken(ctx, gatToken.TokenID, "example")) @@ -275,7 +276,7 @@ func TestGitlabClient_CreateAccessToken_And_Revoke(t *testing.T) { ) require.NoError(t, err) require.NotNil(t, prjatToken) - require.EqualValues(t, gitlab.TokenTypeProject, prjatToken.TokenType) + require.EqualValues(t, token2.TokenTypeProject, prjatToken.TokenType) require.NotEmpty(t, prjatToken.Token) require.NoError(t, client.RevokeProjectAccessToken(ctx, prjatToken.TokenID, "example/example")) @@ -289,7 +290,7 @@ func TestGitlabClient_CreateAccessToken_And_Revoke(t *testing.T) { ) require.NoError(t, err) require.NotNil(t, patToken) - require.EqualValues(t, gitlab.TokenTypePersonal, patToken.TokenType) + require.EqualValues(t, token2.TokenTypePersonal, patToken.TokenType) require.NotEmpty(t, patToken.Token) require.NoError(t, client.RevokePersonalAccessToken(ctx, patToken.TokenID)) } diff --git a/helpers_test.go b/helpers_test.go index 1a4970f..a3d12c9 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -28,6 +28,7 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/flags" + t "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) var _ gitlab.Client = new(inMemoryClient) @@ -226,7 +227,7 @@ func (i *inMemoryClient) CreateProjectDeployToken(ctx context.Context, path stri } i.internalCounter++ var tokenId = i.internalCounter - key := fmt.Sprintf("%s_%v_%v", gitlab.TokenTypeProjectDeploy.String(), projectId, tokenId) + key := fmt.Sprintf("%s_%v_%v", t.TokenTypeProjectDeploy.String(), projectId, tokenId) var entryToken = &gitlab.TokenProjectDeploy{ TokenWithScopes: gitlab.TokenWithScopes{ Token: gitlab.Token{ @@ -235,7 +236,7 @@ func (i *inMemoryClient) CreateProjectDeployToken(ctx context.Context, path stri Path: path, Name: name, Token: fmt.Sprintf("glpat-%s", uuid.New().String()), - TokenType: gitlab.TokenTypeProjectDeploy, + TokenType: t.TokenTypeProjectDeploy, ExpiresAt: expiresAt, CreatedAt: g.Ptr(time.Now())}, Scopes: scopes, @@ -254,7 +255,7 @@ func (i *inMemoryClient) CreateGroupDeployToken(ctx context.Context, path string } i.internalCounter++ var tokenId = i.internalCounter - key := fmt.Sprintf("%s_%v_%v", gitlab.TokenTypeGroupDeploy.String(), groupId, tokenId) + key := fmt.Sprintf("%s_%v_%v", t.TokenTypeGroupDeploy.String(), groupId, tokenId) var entryToken = &gitlab.TokenGroupDeploy{ TokenWithScopes: gitlab.TokenWithScopes{ Token: gitlab.Token{ @@ -263,7 +264,7 @@ func (i *inMemoryClient) CreateGroupDeployToken(ctx context.Context, path string Path: path, Name: name, Token: fmt.Sprintf("glpat-%s", uuid.New().String()), - TokenType: gitlab.TokenTypeGroupDeploy, + TokenType: t.TokenTypeGroupDeploy, ExpiresAt: expiresAt, CreatedAt: g.Ptr(time.Now()), }, @@ -281,7 +282,7 @@ func (i *inMemoryClient) RevokeProjectDeployToken(ctx context.Context, projectId if i.revokeProjectDeployTokenError { return errors.New("revoke project deploy token error") } - key := fmt.Sprintf("%s_%v_%v", gitlab.TokenTypeProjectDeploy.String(), projectId, deployTokenId) + key := fmt.Sprintf("%s_%v_%v", t.TokenTypeProjectDeploy.String(), projectId, deployTokenId) delete(i.accessTokens, key) return nil } @@ -292,7 +293,7 @@ func (i *inMemoryClient) RevokeGroupDeployToken(ctx context.Context, groupId, de if i.revokeGroupDeployTokenError { return errors.New("revoke group deploy token error") } - key := fmt.Sprintf("%s_%v_%v", gitlab.TokenTypeGroupDeploy.String(), groupId, deployTokenId) + key := fmt.Sprintf("%s_%v_%v", t.TokenTypeGroupDeploy.String(), groupId, deployTokenId) delete(i.accessTokens, key) return nil } @@ -316,7 +317,7 @@ func (i *inMemoryClient) CreatePipelineProjectTriggerAccessToken(ctx context.Con } i.internalCounter++ var tokenId = i.internalCounter - key := fmt.Sprintf("%s_%v_%v", gitlab.TokenTypePipelineProjectTrigger.String(), projectId, tokenId) + key := fmt.Sprintf("%s_%v_%v", t.TokenTypePipelineProjectTrigger.String(), projectId, tokenId) var entryToken = &gitlab.TokenPipelineProjectTrigger{ Token: gitlab.Token{ TokenID: tokenId, @@ -324,7 +325,7 @@ func (i *inMemoryClient) CreatePipelineProjectTriggerAccessToken(ctx context.Con Path: strconv.Itoa(projectId), Name: name, Token: fmt.Sprintf("glptt-%s", uuid.New().String()), - TokenType: gitlab.TokenTypePipelineProjectTrigger, + TokenType: t.TokenTypePipelineProjectTrigger, ExpiresAt: expiresAt, CreatedAt: g.Ptr(time.Now()), }, @@ -339,7 +340,7 @@ func (i *inMemoryClient) RevokePipelineProjectTriggerAccessToken(ctx context.Con if i.revokePipelineProjectTriggerAccessTokenError { return fmt.Errorf("RevokePipelineProjectTriggerAccessToken") } - key := fmt.Sprintf("%s_%v_%v", gitlab.TokenTypePipelineProjectTrigger.String(), projectId, tokenId) + key := fmt.Sprintf("%s_%v_%v", t.TokenTypePipelineProjectTrigger.String(), projectId, tokenId) delete(i.accessTokens, key) return nil } @@ -373,16 +374,16 @@ func (i *inMemoryClient) CreateUserServiceAccountAccessToken(ctx context.Context return nil, fmt.Errorf("CreateUserServiceAccountAccessToken") } i.muLock.Unlock() - var t *gitlab.TokenUserServiceAccount + var tok *gitlab.TokenUserServiceAccount var err error var cpat *gitlab.TokenPersonal if cpat, err = i.CreatePersonalAccessToken(ctx, username, userId, name, expiresAt, scopes); err != nil && cpat != nil { - t = &gitlab.TokenUserServiceAccount{ + tok = &gitlab.TokenUserServiceAccount{ TokenWithScopes: gitlab.TokenWithScopes{ Token: gitlab.Token{ CreatedAt: cpat.CreatedAt, ExpiresAt: cpat.ExpiresAt, - TokenType: gitlab.TokenTypeUserServiceAccount, + TokenType: t.TokenTypeUserServiceAccount, Token: cpat.Token.Token, TokenID: cpat.TokenID, ParentID: cpat.ParentID, @@ -394,7 +395,7 @@ func (i *inMemoryClient) CreateUserServiceAccountAccessToken(ctx context.Context } } - return t, err + return tok, err } func (i *inMemoryClient) RevokeUserServiceAccountAccessToken(ctx context.Context, token string) error { @@ -403,7 +404,7 @@ func (i *inMemoryClient) RevokeUserServiceAccountAccessToken(ctx context.Context if i.revokeUserServiceAccountPersonalAccessTokenError { return errors.New("RevokeServiceAccountPersonalAccessToken") } - delete(i.accessTokens, fmt.Sprintf("%s_%v", gitlab.TokenTypeUserServiceAccount.String(), token)) + delete(i.accessTokens, fmt.Sprintf("%s_%v", t.TokenTypeUserServiceAccount.String(), token)) return nil } @@ -413,7 +414,7 @@ func (i *inMemoryClient) RevokeGroupServiceAccountAccessToken(ctx context.Contex if i.revokeGroupServiceAccountPersonalAccessTokenError { return errors.New("RevokeServiceAccountPersonalAccessToken") } - delete(i.accessTokens, fmt.Sprintf("%s_%v", gitlab.TokenTypeGroupServiceAccount.String(), token)) + delete(i.accessTokens, fmt.Sprintf("%s_%v", t.TokenTypeGroupServiceAccount.String(), token)) return nil } @@ -454,7 +455,7 @@ func (i *inMemoryClient) CreatePersonalAccessToken(ctx context.Context, username Path: username, Name: name, Token: fmt.Sprintf("glpat-%s", uuid.New().String()), - TokenType: gitlab.TokenTypePersonal, + TokenType: t.TokenTypePersonal, CreatedAt: g.Ptr(time.Now()), ExpiresAt: &expiresAt, }, @@ -462,7 +463,7 @@ func (i *inMemoryClient) CreatePersonalAccessToken(ctx context.Context, username }, UserID: userId, } - i.accessTokens[fmt.Sprintf("%s_%v", gitlab.TokenTypePersonal.String(), tokenId)] = entryToken + i.accessTokens[fmt.Sprintf("%s_%v", t.TokenTypePersonal.String(), tokenId)] = entryToken return entryToken, nil } @@ -482,7 +483,7 @@ func (i *inMemoryClient) CreateGroupAccessToken(ctx context.Context, groupId str Path: groupId, Name: name, Token: fmt.Sprintf("glgat-%s", uuid.New().String()), - TokenType: gitlab.TokenTypeGroup, + TokenType: t.TokenTypeGroup, CreatedAt: g.Ptr(time.Now()), ExpiresAt: &expiresAt, }, @@ -490,7 +491,7 @@ func (i *inMemoryClient) CreateGroupAccessToken(ctx context.Context, groupId str AccessLevel: accessLevel, }, } - i.accessTokens[fmt.Sprintf("%s_%v", gitlab.TokenTypeGroup.String(), tokenId)] = entryToken + i.accessTokens[fmt.Sprintf("%s_%v", t.TokenTypeGroup.String(), tokenId)] = entryToken return entryToken, nil } @@ -506,7 +507,7 @@ func (i *inMemoryClient) CreateProjectAccessToken(ctx context.Context, projectId TokenWithScopesAndAccessLevel: gitlab.TokenWithScopesAndAccessLevel{ Token: gitlab.Token{ Token: fmt.Sprintf("glpat-%s", uuid.New().String()), - TokenType: gitlab.TokenTypeProject, + TokenType: t.TokenTypeProject, CreatedAt: g.Ptr(time.Now()), ExpiresAt: &expiresAt, TokenID: tokenId, @@ -518,7 +519,7 @@ func (i *inMemoryClient) CreateProjectAccessToken(ctx context.Context, projectId AccessLevel: accessLevel, }, } - i.accessTokens[fmt.Sprintf("%s_%v", gitlab.TokenTypeProject.String(), tokenId)] = entryToken + i.accessTokens[fmt.Sprintf("%s_%v", t.TokenTypeProject.String(), tokenId)] = entryToken return entryToken, nil } @@ -528,7 +529,7 @@ func (i *inMemoryClient) RevokePersonalAccessToken(ctx context.Context, tokenId if i.personalAccessTokenRevokeError { return fmt.Errorf("RevokePersonalAccessToken") } - delete(i.accessTokens, fmt.Sprintf("%s_%v", gitlab.TokenTypePersonal.String(), tokenId)) + delete(i.accessTokens, fmt.Sprintf("%s_%v", t.TokenTypePersonal.String(), tokenId)) return nil } @@ -538,7 +539,7 @@ func (i *inMemoryClient) RevokeProjectAccessToken(ctx context.Context, tokenId i if i.projectAccessTokenRevokeError { return fmt.Errorf("RevokeProjectAccessToken") } - delete(i.accessTokens, fmt.Sprintf("%s_%v", gitlab.TokenTypeProject.String(), tokenId)) + delete(i.accessTokens, fmt.Sprintf("%s_%v", t.TokenTypeProject.String(), tokenId)) return nil } @@ -548,7 +549,7 @@ func (i *inMemoryClient) RevokeGroupAccessToken(ctx context.Context, tokenId int if i.groupAccessTokenRevokeError { return fmt.Errorf("RevokeGroupAccessToken") } - delete(i.accessTokens, fmt.Sprintf("%s_%v", gitlab.TokenTypeGroup.String(), tokenId)) + delete(i.accessTokens, fmt.Sprintf("%s_%v", t.TokenTypeGroup.String(), tokenId)) return nil } diff --git a/type_token_type.go b/internal/token/type.go similarity index 93% rename from type_token_type.go rename to internal/token/type.go index 315e029..142d995 100644 --- a/type_token_type.go +++ b/internal/token/type.go @@ -1,4 +1,4 @@ -package gitlab +package token import ( "errors" @@ -24,7 +24,7 @@ const ( var ( ErrUnknownTokenType = errors.New("unknown token type") - validTokenTypes = []string{ + ValidTokenTypes = []string{ TokenTypePersonal.String(), TokenTypeProject.String(), TokenTypeGroup.String(), @@ -45,7 +45,7 @@ func (i TokenType) Value() string { } func TokenTypeParse(value string) (TokenType, error) { - if slices.Contains(validTokenTypes, value) { + if slices.Contains(ValidTokenTypes, value) { return TokenType(value), nil } return TokenTypeUnknown, fmt.Errorf("failed to parse '%s': %w", value, ErrUnknownTokenType) diff --git a/type_token_type_test.go b/internal/token/type_test.go similarity index 94% rename from type_token_type_test.go rename to internal/token/type_test.go index 561a4e1..19b9aff 100644 --- a/type_token_type_test.go +++ b/internal/token/type_test.go @@ -1,13 +1,13 @@ //go:build unit -package gitlab_test +package token_test import ( "testing" "github.com/stretchr/testify/assert" - gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestTokenType(t *testing.T) { diff --git a/name_tpl_rand_string_test.go b/name_tpl_rand_string_test.go index f079f87..86cc711 100644 --- a/name_tpl_rand_string_test.go +++ b/name_tpl_rand_string_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/require" g "github.com/ilijamt/vault-plugin-secrets-gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestTokenNameGenerator_RandString(t *testing.T) { @@ -20,7 +21,7 @@ func TestTokenNameGenerator_RandString(t *testing.T) { Name: "{{ randHexString 8 }}", Scopes: []string{g.TokenScopeApi.String()}, AccessLevel: g.AccessLevelNoPermissions, - TokenType: g.TokenTypePersonal, + TokenType: token.TokenTypePersonal, GitlabRevokesTokens: false, }, ) diff --git a/name_tpl_test.go b/name_tpl_test.go index dd534b8..cfa64ff 100644 --- a/name_tpl_test.go +++ b/name_tpl_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/assert" g "github.com/ilijamt/vault-plugin-secrets-gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestTokenNameGenerator(t *testing.T) { @@ -29,7 +30,7 @@ func TestTokenNameGenerator(t *testing.T) { Name: "{{ .role_name", Scopes: []string{g.TokenScopeApi.String()}, AccessLevel: g.AccessLevelNoPermissions, - TokenType: g.TokenTypePersonal, + TokenType: token.TokenTypePersonal, GitlabRevokesTokens: true, }, "", @@ -45,7 +46,7 @@ func TestTokenNameGenerator(t *testing.T) { Name: "{{ .role_name }}-{{ .token_type }}-access-token-{{ yesNoBool .gitlab_revokes_token }}", Scopes: []string{g.TokenScopeApi.String()}, AccessLevel: g.AccessLevelNoPermissions, - TokenType: g.TokenTypePersonal, + TokenType: token.TokenTypePersonal, GitlabRevokesTokens: true, }, "test-personal-access-token-yes", @@ -61,7 +62,7 @@ func TestTokenNameGenerator(t *testing.T) { Name: "{{ .role_name }}-{{ .token_type }}-{{ stringsJoin .scopes \"-\" }}-{{ yesNoBool .gitlab_revokes_token }}", Scopes: []string{g.TokenScopeApi.String(), g.TokenScopeSudo.String()}, AccessLevel: g.AccessLevelNoPermissions, - TokenType: g.TokenTypePersonal, + TokenType: token.TokenTypePersonal, GitlabRevokesTokens: false, }, "test-personal-api-sudo-no", @@ -77,7 +78,7 @@ func TestTokenNameGenerator(t *testing.T) { Name: "{{ .role_name }}-{{ .token_type }}-{{ timeNowFormat \"2006-01\" }}", Scopes: []string{g.TokenScopeApi.String(), g.TokenScopeSudo.String()}, AccessLevel: g.AccessLevelNoPermissions, - TokenType: g.TokenTypePersonal, + TokenType: token.TokenTypePersonal, GitlabRevokesTokens: false, }, fmt.Sprintf("test-personal-%d-%02d", time.Now().UTC().Year(), time.Now().UTC().Month()), diff --git a/name_tpl_unix_timestamp_test.go b/name_tpl_unix_timestamp_test.go index 7579786..7a133b9 100644 --- a/name_tpl_unix_timestamp_test.go +++ b/name_tpl_unix_timestamp_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" g "github.com/ilijamt/vault-plugin-secrets-gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestTokenNameGenerator_UnixTimeStamp(t *testing.T) { @@ -22,7 +23,7 @@ func TestTokenNameGenerator_UnixTimeStamp(t *testing.T) { Name: "{{ .unix_timestamp_utc }}", Scopes: []string{g.TokenScopeApi.String()}, AccessLevel: g.AccessLevelNoPermissions, - TokenType: g.TokenTypePersonal, + TokenType: token.TokenTypePersonal, GitlabRevokesTokens: false, }, ) diff --git a/path_role.go b/path_role.go index 1113b33..3951406 100644 --- a/path_role.go +++ b/path_role.go @@ -17,6 +17,7 @@ import ( "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) @@ -81,7 +82,7 @@ var ( Type: framework.TypeString, Description: "access token type", Required: true, - AllowedValues: utils.ToAny(validTokenTypes...), + AllowedValues: utils.ToAny(token.ValidTokenTypes...), DisplayAttrs: &framework.DisplayAttributes{ Name: "Token Type", }, @@ -203,7 +204,7 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data var config *EntryConfig var err error var warnings []string - var tokenType TokenType + var tokenType token.TokenType var accessLevel AccessLevel var configName = cmp.Or(data.Get("config_name").(string), TypeConfigDefault) @@ -218,7 +219,7 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data return logical.ErrorResponse(errs.ErrBackendNotConfigured.Error()), nil } - tokenType, _ = TokenTypeParse(data.Get("token_type").(string)) + tokenType, _ = token.TokenTypeParse(data.Get("token_type").(string)) accessLevel, _ = AccessLevelParse(data.Get("access_level").(string)) var role = EntryRole{ @@ -239,8 +240,8 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data } // validate token type - if !slices.Contains(validTokenTypes, tokenType.String()) { - err = multierror.Append(err, fmt.Errorf("token_type='%s', should be one of %v: %w", data.Get("token_type").(string), validTokenTypes, errs.ErrFieldInvalidValue)) + if !slices.Contains(token.ValidTokenTypes, tokenType.String()) { + err = multierror.Append(err, fmt.Errorf("token_type='%s', should be one of %v: %w", data.Get("token_type").(string), token.ValidTokenTypes, errs.ErrFieldInvalidValue)) } // validate access level and which fields to skip for validation @@ -250,42 +251,42 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data var skipFields []string switch tokenType { - case TokenTypePersonal: + case token.TokenTypePersonal: validAccessLevels = ValidPersonalAccessLevels validScopes = ValidPersonalTokenScopes noEmptyScopes = false skipFields = []string{"config_name", "access_level"} - case TokenTypeGroup: + case token.TokenTypeGroup: validAccessLevels = ValidGroupAccessLevels validScopes = ValidGroupTokenScopes noEmptyScopes = false skipFields = []string{"config_name"} - case TokenTypeProject: + case token.TokenTypeProject: validAccessLevels = ValidProjectAccessLevels validScopes = ValidProjectTokenScopes noEmptyScopes = false skipFields = []string{"config_name"} - case TokenTypeUserServiceAccount: + case token.TokenTypeUserServiceAccount: validAccessLevels = ValidUserServiceAccountAccessLevels validScopes = ValidUserServiceAccountTokenScopes noEmptyScopes = false skipFields = []string{"config_name", "access_level"} - case TokenTypeGroupServiceAccount: + case token.TokenTypeGroupServiceAccount: validAccessLevels = ValidGroupServiceAccountAccessLevels validScopes = ValidGroupServiceAccountTokenScopes noEmptyScopes = false skipFields = []string{"config_name", "access_level"} - case TokenTypePipelineProjectTrigger: + case token.TokenTypePipelineProjectTrigger: validAccessLevels = ValidPipelineProjectTriggerAccessLevels validScopes = []string{} noEmptyScopes = false skipFields = []string{"config_name", "access_level", "scopes"} - case TokenTypeProjectDeploy: + case token.TokenTypeProjectDeploy: validAccessLevels = ValidProjectDeployAccessLevels validScopes = ValidProjectDeployTokenScopes noEmptyScopes = true skipFields = []string{"config_name", "access_level"} - case TokenTypeGroupDeploy: + case token.TokenTypeGroupDeploy: validAccessLevels = ValidGroupDeployAccessLevels validScopes = ValidGroupDeployTokenScopes noEmptyScopes = true @@ -301,13 +302,13 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data } val, ok, _ := data.GetOkErr(name) - if (tokenType == TokenTypePersonal && name == "access_level") || + if (tokenType == token.TokenTypePersonal && name == "access_level") || name == "gitlab_revokes_token" { continue } var required = field.Required - if name == "ttl" && !slices.Contains([]TokenType{TokenTypePipelineProjectTrigger}, tokenType) { + if name == "ttl" && !slices.Contains([]token.TokenType{token.TokenTypePipelineProjectTrigger}, tokenType) { required = true } @@ -348,7 +349,7 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data err = multierror.Append(err, fmt.Errorf("should be one or more of '%v': %w", validScopes, errs.ErrFieldInvalidValue)) } - if tokenType == TokenTypeUserServiceAccount && (config.Type == gitlab.TypeSaaS || config.Type == gitlab.TypeDedicated) { + if tokenType == token.TokenTypeUserServiceAccount && (config.Type == gitlab.TypeSaaS || config.Type == gitlab.TypeDedicated) { err = multierror.Append(err, fmt.Errorf("cannot create %s with %s: %w", tokenType, config.Type, errs.ErrInvalidValue)) } diff --git a/path_role_deploy_tokens_test.go b/path_role_deploy_tokens_test.go index bde2e09..f703e34 100644 --- a/path_role_deploy_tokens_test.go +++ b/path_role_deploy_tokens_test.go @@ -17,6 +17,7 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestPathRolesDeployTokens(t *testing.T) { @@ -27,7 +28,7 @@ func TestPathRolesDeployTokens(t *testing.T) { } var tests = []struct { - tokenType gitlab.TokenType + tokenType token.TokenType accessLevel gitlab.AccessLevel scopes []string ttl string @@ -35,12 +36,12 @@ func TestPathRolesDeployTokens(t *testing.T) { name string }{ { - tokenType: gitlab.TokenTypeProjectDeploy, + tokenType: token.TokenTypeProjectDeploy, path: "example/example", scopes: []string{gitlab.TokenScopeReadRepository.String()}, }, { - tokenType: gitlab.TokenTypeGroupDeploy, + tokenType: token.TokenTypeGroupDeploy, path: "test/test1", scopes: []string{gitlab.TokenScopeReadRepository.String()}, }, diff --git a/path_role_pipeline_project_trigger_token_test.go b/path_role_pipeline_project_trigger_token_test.go index 042162b..87c5ccc 100644 --- a/path_role_pipeline_project_trigger_token_test.go +++ b/path_role_pipeline_project_trigger_token_test.go @@ -17,6 +17,7 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestPathRolesPipelineProjectTrigger(t *testing.T) { @@ -37,7 +38,7 @@ func TestPathRolesPipelineProjectTrigger(t *testing.T) { "path": "user", "name": "Example user personal token", "access_level": gitlab.AccessLevelNoPermissions.String(), - "token_type": gitlab.TokenTypePipelineProjectTrigger.String(), + "token_type": token.TokenTypePipelineProjectTrigger.String(), "scopes": []string{gitlab.TokenScopeApi.String()}, "ttl": "1h", }, @@ -59,7 +60,7 @@ func TestPathRolesPipelineProjectTrigger(t *testing.T) { "path": "user", "name": "Example user personal token", "access_level": gitlab.AccessLevelUnknown.String(), - "token_type": gitlab.TokenTypePipelineProjectTrigger.String(), + "token_type": token.TokenTypePipelineProjectTrigger.String(), "scopes": []string{}, "ttl": "1h", }, @@ -80,7 +81,7 @@ func TestPathRolesPipelineProjectTrigger(t *testing.T) { "path": "user", "name": "Example user personal token", "access_level": gitlab.AccessLevelUnknown.String(), - "token_type": gitlab.TokenTypePipelineProjectTrigger.String(), + "token_type": token.TokenTypePipelineProjectTrigger.String(), "scopes": []string{}, }, }) diff --git a/path_role_test.go b/path_role_test.go index 800434e..d34d27d 100644 --- a/path_role_test.go +++ b/path_role_test.go @@ -17,6 +17,7 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestPathRolesList(t *testing.T) { @@ -69,7 +70,7 @@ func TestPathRoles(t *testing.T) { }) t.Run("access level", func(t *testing.T) { - t.Run(gitlab.TokenTypePersonal.String(), func(t *testing.T) { + t.Run(token.TokenTypePersonal.String(), func(t *testing.T) { t.Run("no access level defined", func(t *testing.T) { ctx := getCtxGitlabClient(t, "unit") var b, l, err = getBackendWithConfig(ctx, defaultConfig) @@ -79,8 +80,8 @@ func TestPathRoles(t *testing.T) { Path: fmt.Sprintf("%s/test", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "user", - "name": gitlab.TokenTypePersonal.String(), - "token_type": gitlab.TokenTypePersonal.String(), + "name": token.TokenTypePersonal.String(), + "token_type": token.TokenTypePersonal.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": gitlab.ValidPersonalTokenScopes, "gitlab_revokes_token": false, @@ -100,9 +101,9 @@ func TestPathRoles(t *testing.T) { Path: fmt.Sprintf("%s/test", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "user", - "name": gitlab.TokenTypePersonal.String(), + "name": token.TokenTypePersonal.String(), "access_level": gitlab.AccessLevelOwnerPermissions.String(), - "token_type": gitlab.TokenTypePersonal.String(), + "token_type": token.TokenTypePersonal.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": gitlab.ValidPersonalTokenScopes, "gitlab_revokes_token": false, @@ -114,7 +115,7 @@ func TestPathRoles(t *testing.T) { }) }) - t.Run(gitlab.TokenTypeProject.String(), func(t *testing.T) { + t.Run(token.TokenTypeProject.String(), func(t *testing.T) { t.Run("no access level defined", func(t *testing.T) { ctx := getCtxGitlabClient(t, "unit") var b, l, err = getBackendWithConfig(ctx, defaultConfig) @@ -124,8 +125,8 @@ func TestPathRoles(t *testing.T) { Path: fmt.Sprintf("%s/test", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "user", - "name": gitlab.TokenTypeProject.String(), - "token_type": gitlab.TokenTypeProject.String(), + "name": token.TokenTypeProject.String(), + "token_type": token.TokenTypeProject.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": gitlab.ValidProjectTokenScopes, "gitlab_revokes_token": false, @@ -144,9 +145,9 @@ func TestPathRoles(t *testing.T) { Path: fmt.Sprintf("%s/test", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "user", - "name": gitlab.TokenTypeProject.String(), + "name": token.TokenTypeProject.String(), "access_level": gitlab.AccessLevelOwnerPermissions.String(), - "token_type": gitlab.TokenTypeProject.String(), + "token_type": token.TokenTypeProject.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": gitlab.ValidProjectTokenScopes, "gitlab_revokes_token": false, @@ -159,7 +160,7 @@ func TestPathRoles(t *testing.T) { }) }) - t.Run(gitlab.TokenTypeGroup.String(), func(t *testing.T) { + t.Run(token.TokenTypeGroup.String(), func(t *testing.T) { t.Run("no access level defined", func(t *testing.T) { ctx := getCtxGitlabClient(t, "unit") var b, l, err = getBackendWithConfig(ctx, defaultConfig) @@ -169,8 +170,8 @@ func TestPathRoles(t *testing.T) { Path: fmt.Sprintf("%s/test", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "user", - "name": gitlab.TokenTypeGroup.String(), - "token_type": gitlab.TokenTypeGroup.String(), + "name": token.TokenTypeGroup.String(), + "token_type": token.TokenTypeGroup.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": gitlab.ValidGroupTokenScopes, "gitlab_revokes_token": false, @@ -189,9 +190,9 @@ func TestPathRoles(t *testing.T) { Path: fmt.Sprintf("%s/test", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "user", - "name": gitlab.TokenTypeGroup.String(), + "name": token.TokenTypeGroup.String(), "access_level": gitlab.AccessLevelOwnerPermissions.String(), - "token_type": gitlab.TokenTypeGroup.String(), + "token_type": token.TokenTypeGroup.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": gitlab.ValidGroupTokenScopes, "gitlab_revokes_token": false, @@ -234,7 +235,7 @@ func TestPathRoles(t *testing.T) { Data: map[string]any{ "path": "user", "name": "{{ . } invalid template", - "token_type": gitlab.TokenTypePersonal.String(), + "token_type": token.TokenTypePersonal.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": gitlab.ValidPersonalTokenScopes, "gitlab_revokes_token": false, @@ -259,7 +260,7 @@ func TestPathRoles(t *testing.T) { "name": "Example user personal token", "access_level": gitlab.AccessLevelOwnerPermissions.String(), "ttl": "48h", - "token_type": gitlab.TokenTypeProject.String(), + "token_type": token.TokenTypeProject.String(), "scopes": gitlab.ValidProjectTokenScopes, }, }) @@ -279,7 +280,7 @@ func TestPathRoles(t *testing.T) { "path": "user", "name": "Example project personal token", "access_level": gitlab.AccessLevelOwnerPermissions.String(), - "token_type": gitlab.TokenTypeProject.String(), + "token_type": token.TokenTypeProject.String(), "ttl": "48h", "scopes": gitlab.ValidPersonalTokenScopes, "gitlab_revokes_token": false, @@ -304,7 +305,7 @@ func TestPathRoles(t *testing.T) { "path": "user", "name": "Example user personal token", "ttl": "48h", - "token_type": gitlab.TokenTypePersonal.String(), + "token_type": token.TokenTypePersonal.String(), "scopes": gitlab.ValidPersonalTokenScopes, }, }) @@ -323,7 +324,7 @@ func TestPathRoles(t *testing.T) { Data: map[string]any{ "path": "user", "name": "Example user personal token", - "token_type": gitlab.TokenTypePersonal.String(), + "token_type": token.TokenTypePersonal.String(), "scopes": []string{ "invalid_scope", }, @@ -349,7 +350,7 @@ func TestPathRoles(t *testing.T) { "name": "Example user personal token", "ttl": "48h", "access_level": gitlab.AccessLevelOwnerPermissions.String(), - "token_type": gitlab.TokenTypeGroup.String(), + "token_type": token.TokenTypeGroup.String(), "scopes": gitlab.ValidProjectTokenScopes, }, }) @@ -369,7 +370,7 @@ func TestPathRoles(t *testing.T) { "path": "user", "name": "Example user personal token", "access_level": gitlab.AccessLevelOwnerPermissions.String(), - "token_type": gitlab.TokenTypeGroup.String(), + "token_type": token.TokenTypeGroup.String(), "scopes": gitlab.ValidPersonalTokenScopes, }, }) @@ -419,7 +420,7 @@ func TestPathRoles(t *testing.T) { var roleData = map[string]any{ "path": "user", "name": "Example user personal token", - "token_type": gitlab.TokenTypePersonal.String(), + "token_type": token.TokenTypePersonal.String(), "ttl": int64((5 * 24 * time.Hour).Seconds()), "gitlab_revokes_token": false, "scopes": []string{ diff --git a/path_role_ttl_test.go b/path_role_ttl_test.go index a60aa02..2f21956 100644 --- a/path_role_ttl_test.go +++ b/path_role_ttl_test.go @@ -16,6 +16,7 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestPathRolesTTL(t *testing.T) { @@ -29,7 +30,7 @@ func TestPathRolesTTL(t *testing.T) { var generalRole = map[string]any{ "path": "user", "name": "Example user personal token", - "token_type": gitlab.TokenTypePersonal.String(), + "token_type": token.TokenTypePersonal.String(), "scopes": []string{ gitlab.TokenScopeApi.String(), gitlab.TokenScopeReadRegistry.String(), @@ -90,7 +91,7 @@ func TestPathRolesTTL(t *testing.T) { var generalRole = map[string]any{ "path": "user", "name": "Example user personal token", - "token_type": gitlab.TokenTypePersonal.String(), + "token_type": token.TokenTypePersonal.String(), "scopes": []string{ gitlab.TokenScopeApi.String(), gitlab.TokenScopeReadRegistry.String(), @@ -152,7 +153,7 @@ func TestPathRolesTTL(t *testing.T) { var generalRole = map[string]any{ "path": "user", "name": "Example user personal token", - "token_type": gitlab.TokenTypePersonal.String(), + "token_type": token.TokenTypePersonal.String(), "scopes": []string{ gitlab.TokenScopeApi.String(), gitlab.TokenScopeReadRegistry.String(), diff --git a/path_token_role.go b/path_token_role.go index ed1042f..b1d92ed 100644 --- a/path_token_role.go +++ b/path_token_role.go @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/vault/sdk/logical" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" + token2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) @@ -80,26 +81,26 @@ func (b *Backend) pathTokenRoleCreate(ctx context.Context, req *logical.Request, } switch role.TokenType { - case TokenTypeGroup: + case token2.TokenTypeGroup: b.Logger().Debug("Creating group access token for role", "path", role.Path, "name", name, "expiresAt", expiresAt, "scopes", role.Scopes, "accessLevel", role.AccessLevel) token, err = client.CreateGroupAccessToken(ctx, role.Path, name, expiresAt, role.Scopes, role.AccessLevel) - case TokenTypeProject: + case token2.TokenTypeProject: b.Logger().Debug("Creating project access token for role", "path", role.Path, "name", name, "expiresAt", expiresAt, "scopes", role.Scopes, "accessLevel", role.AccessLevel) token, err = client.CreateProjectAccessToken(ctx, role.Path, name, expiresAt, role.Scopes, role.AccessLevel) - case TokenTypePersonal: + case token2.TokenTypePersonal: var userId int userId, err = client.GetUserIdByUsername(ctx, role.Path) if err == nil { b.Logger().Debug("Creating personal access token for role", "path", role.Path, "userId", userId, "name", name, "expiresAt", expiresAt, "scopes", role.Scopes) token, err = client.CreatePersonalAccessToken(ctx, role.Path, userId, name, expiresAt, role.Scopes) } - case TokenTypeUserServiceAccount: + case token2.TokenTypeUserServiceAccount: var userId int if userId, err = client.GetUserIdByUsername(ctx, role.Path); err == nil { b.Logger().Debug("Creating user service account access token for role", "path", role.Path, "userId", userId, "name", name, "expiresAt", expiresAt, "scopes", role.Scopes) token, err = client.CreateUserServiceAccountAccessToken(ctx, role.Path, userId, name, expiresAt, role.Scopes) } - case TokenTypeGroupServiceAccount: + case token2.TokenTypeGroupServiceAccount: var serviceAccount, groupId string { parts := strings.Split(role.Path, "/") @@ -111,23 +112,23 @@ func (b *Backend) pathTokenRoleCreate(ctx context.Context, req *logical.Request, b.Logger().Debug("Creating group service account access token for role", "path", role.Path, "groupId", groupId, "userId", userId, "name", name, "expiresAt", expiresAt, "scopes", role.Scopes) token, err = client.CreateGroupServiceAccountAccessToken(ctx, role.Path, groupId, userId, name, expiresAt, role.Scopes) } - case TokenTypeProjectDeploy: + case token2.TokenTypeProjectDeploy: var projectId int if projectId, err = client.GetProjectIdByPath(ctx, role.Path); err == nil { token, err = client.CreateProjectDeployToken(ctx, role.Path, projectId, name, &expiresAt, role.Scopes) } - case TokenTypeGroupDeploy: + case token2.TokenTypeGroupDeploy: var groupId int if groupId, err = client.GetGroupIdByPath(ctx, role.Path); err == nil { token, err = client.CreateGroupDeployToken(ctx, role.Path, groupId, name, &expiresAt, role.Scopes) } - case TokenTypePipelineProjectTrigger: + case token2.TokenTypePipelineProjectTrigger: var projectId int if projectId, err = client.GetProjectIdByPath(ctx, role.Path); err == nil { token, err = client.CreatePipelineProjectTriggerAccessToken(ctx, role.Path, name, projectId, name, &expiresAt) } default: - return logical.ErrorResponse("invalid token type"), fmt.Errorf("%s: %w", role.TokenType.String(), ErrUnknownTokenType) + return logical.ErrorResponse("invalid token type"), fmt.Errorf("%s: %w", role.TokenType.String(), token2.ErrUnknownTokenType) } if err != nil || token == nil { diff --git a/path_token_role_multiple_config_test.go b/path_token_role_multiple_config_test.go index 6bc4273..e277b4a 100644 --- a/path_token_role_multiple_config_test.go +++ b/path_token_role_multiple_config_test.go @@ -12,6 +12,7 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestPathTokenRolesMultipleConfigs(t *testing.T) { @@ -45,7 +46,7 @@ func TestPathTokenRolesMultipleConfigs(t *testing.T) { type roleData struct { roleName, path, tokenName string - tokenType gitlab.TokenType + tokenType token.TokenType accessLevel gitlab.AccessLevel scopes []string } @@ -54,14 +55,14 @@ func TestPathTokenRolesMultipleConfigs(t *testing.T) { { roleName: "root-root", path: "root", - tokenType: gitlab.TokenTypePersonal, + tokenType: token.TokenTypePersonal, scopes: []string{gitlab.TokenScopeApi.String(), gitlab.TokenScopeSelfRotate.String()}, tokenName: "admin_user_root", }, { roleName: "root-normal-user", path: "normal-user", - tokenType: gitlab.TokenTypePersonal, + tokenType: token.TokenTypePersonal, scopes: []string{gitlab.TokenScopeApi.String(), gitlab.TokenScopeSelfRotate.String()}, tokenName: "admin_user_root", }, @@ -70,7 +71,7 @@ func TestPathTokenRolesMultipleConfigs(t *testing.T) { { roleName: "admin-example-example", path: "example/example", - tokenType: gitlab.TokenTypeProject, + tokenType: token.TokenTypeProject, accessLevel: gitlab.AccessLevelGuestPermissions, scopes: []string{gitlab.TokenScopeApi.String(), gitlab.TokenScopeSelfRotate.String()}, tokenName: "admin_user_initial_token", @@ -80,7 +81,7 @@ func TestPathTokenRolesMultipleConfigs(t *testing.T) { { roleName: "normal-example", path: "example", - tokenType: gitlab.TokenTypeGroup, + tokenType: token.TokenTypeGroup, accessLevel: gitlab.AccessLevelGuestPermissions, scopes: []string{gitlab.TokenScopeApi.String(), gitlab.TokenScopeSelfRotate.String()}, tokenName: "normal_user_initial_token", @@ -97,13 +98,13 @@ func TestPathTokenRolesMultipleConfigs(t *testing.T) { } switch rd.tokenType { - case gitlab.TokenTypePersonal: + case token.TokenTypePersonal: data["access_level"] = rd.accessLevel.String() data["scopes"] = rd.scopes - case gitlab.TokenTypeGroup: + case token.TokenTypeGroup: data["access_level"] = rd.accessLevel.String() data["scopes"] = rd.scopes - case gitlab.TokenTypeProject: + case token.TokenTypeProject: data["access_level"] = rd.accessLevel.String() data["scopes"] = rd.scopes } diff --git a/path_token_role_test.go b/path_token_role_test.go index 3160e33..ab3984f 100644 --- a/path_token_role_test.go +++ b/path_token_role_test.go @@ -14,6 +14,7 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestPathTokenRoles(t *testing.T) { @@ -36,7 +37,7 @@ func TestPathTokenRoles(t *testing.T) { require.ErrorIs(t, err, gitlab.ErrRoleNotFound) }) - var generalTokenCreation = func(t *testing.T, tokenType gitlab.TokenType, level gitlab.AccessLevel, gitlabRevokesToken bool) { + var generalTokenCreation = func(t *testing.T, tokenType token.TokenType, level gitlab.AccessLevel, gitlabRevokesToken bool) { t.Logf("token creation, token type: %s, level: %s, gitlab revokes token: %t", tokenType, level, gitlabRevokesToken) ctx := getCtxGitlabClient(t, "unit") client := newInMemoryClient(true) @@ -57,11 +58,11 @@ func TestPathTokenRoles(t *testing.T) { var path string switch tokenType { - case gitlab.TokenTypeProject: + case token.TokenTypeProject: path = "example/example" - case gitlab.TokenTypePersonal: + case token.TokenTypePersonal: path = "admin-user" - case gitlab.TokenTypeGroup: + case token.TokenTypeGroup: path = "example" } @@ -124,11 +125,11 @@ func TestPathTokenRoles(t *testing.T) { if !gitlabRevokesToken { // calling revoke again would return a token not found in internal error switch tokenType { - case gitlab.TokenTypeProject: + case token.TokenTypeProject: client.projectAccessTokenRevokeError = true - case gitlab.TokenTypePersonal: + case token.TokenTypePersonal: client.personalAccessTokenRevokeError = true - case gitlab.TokenTypeGroup: + case token.TokenTypeGroup: client.groupAccessTokenRevokeError = true } resp, err = b.HandleRequest(ctx, &logical.Request{ @@ -151,17 +152,17 @@ func TestPathTokenRoles(t *testing.T) { } t.Run("personal access token", func(t *testing.T) { - generalTokenCreation(t, gitlab.TokenTypePersonal, gitlab.AccessLevelUnknown, false) - generalTokenCreation(t, gitlab.TokenTypePersonal, gitlab.AccessLevelUnknown, true) + generalTokenCreation(t, token.TokenTypePersonal, gitlab.AccessLevelUnknown, false) + generalTokenCreation(t, token.TokenTypePersonal, gitlab.AccessLevelUnknown, true) }) t.Run("project access token", func(t *testing.T) { - generalTokenCreation(t, gitlab.TokenTypeProject, gitlab.AccessLevelGuestPermissions, false) - generalTokenCreation(t, gitlab.TokenTypeProject, gitlab.AccessLevelGuestPermissions, true) + generalTokenCreation(t, token.TokenTypeProject, gitlab.AccessLevelGuestPermissions, false) + generalTokenCreation(t, token.TokenTypeProject, gitlab.AccessLevelGuestPermissions, true) }) t.Run("group access token", func(t *testing.T) { - generalTokenCreation(t, gitlab.TokenTypeGroup, gitlab.AccessLevelGuestPermissions, false) - generalTokenCreation(t, gitlab.TokenTypeGroup, gitlab.AccessLevelGuestPermissions, true) + generalTokenCreation(t, token.TokenTypeGroup, gitlab.AccessLevelGuestPermissions, false) + generalTokenCreation(t, token.TokenTypeGroup, gitlab.AccessLevelGuestPermissions, true) }) } diff --git a/secret_access_tokens.go b/secret_access_tokens.go index edb66ea..6dfb732 100644 --- a/secret_access_tokens.go +++ b/secret_access_tokens.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/vault/sdk/logical" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) @@ -80,9 +81,9 @@ func (b *Backend) secretAccessTokenRevoke(ctx context.Context, req *logical.Requ var gitlabRevokesToken = req.Secret.InternalData["gitlab_revokes_token"].(bool) var vaultRevokesToken = !gitlabRevokesToken var parentId = req.Secret.InternalData["parent_id"].(string) - var tokenType TokenType + var tokenType token.TokenType var tokenTypeValue = req.Secret.InternalData["token_type"].(string) - tokenType, _ = TokenTypeParse(tokenTypeValue) + tokenType, _ = token.TokenTypeParse(tokenTypeValue) if vaultRevokesToken { var client Client @@ -92,29 +93,29 @@ func (b *Backend) secretAccessTokenRevoke(ctx context.Context, req *logical.Requ } switch tokenType { - case TokenTypePersonal: + case token.TokenTypePersonal: err = client.RevokePersonalAccessToken(ctx, tokenId) - case TokenTypeProject: + case token.TokenTypeProject: err = client.RevokeProjectAccessToken(ctx, tokenId, parentId) - case TokenTypeGroup: + case token.TokenTypeGroup: err = client.RevokeGroupAccessToken(ctx, tokenId, parentId) - case TokenTypeUserServiceAccount: + case token.TokenTypeUserServiceAccount: var token = req.Secret.InternalData["token"].(string) err = client.RevokeUserServiceAccountAccessToken(ctx, token) - case TokenTypeGroupServiceAccount: + case token.TokenTypeGroupServiceAccount: var token = req.Secret.InternalData["token"].(string) err = client.RevokeGroupServiceAccountAccessToken(ctx, token) - case TokenTypePipelineProjectTrigger: + case token.TokenTypePipelineProjectTrigger: var projectId int if projectId, err = strconv.Atoi(parentId); err == nil { err = client.RevokePipelineProjectTriggerAccessToken(ctx, projectId, tokenId) } - case TokenTypeGroupDeploy: + case token.TokenTypeGroupDeploy: var groupId int if groupId, err = strconv.Atoi(parentId); err == nil { err = client.RevokeGroupDeployToken(ctx, groupId, tokenId) } - case TokenTypeProjectDeploy: + case token.TokenTypeProjectDeploy: var projectId int if projectId, err = strconv.Atoi(parentId); err == nil { err = client.RevokeProjectDeployToken(ctx, projectId, tokenId) diff --git a/token.go b/token.go index 4752b08..6187235 100644 --- a/token.go +++ b/token.go @@ -6,13 +6,15 @@ import ( "maps" "strconv" "time" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) type IToken interface { Internal() map[string]any Data() map[string]any Event(map[string]string) map[string]string - Type() TokenType + Type() token.TokenType SetConfigName(string) SetRoleName(string) SetGitlabRevokesToken(bool) @@ -23,17 +25,17 @@ type IToken interface { } type Token struct { - RoleName string `json:"role_name"` - ConfigName string `json:"config_name"` - GitlabRevokesToken bool `json:"gitlab_revokes_token"` - CreatedAt *time.Time `json:"created_at"` - ExpiresAt *time.Time `json:"expires_at"` - TokenType TokenType `json:"type"` - Token string `json:"token"` - TokenID int `json:"token_id"` - ParentID string `json:"parent_id"` - Name string `json:"name"` - Path string `json:"path"` + RoleName string `json:"role_name"` + ConfigName string `json:"config_name"` + GitlabRevokesToken bool `json:"gitlab_revokes_token"` + CreatedAt *time.Time `json:"created_at"` + ExpiresAt *time.Time `json:"expires_at"` + TokenType token.TokenType `json:"type"` + Token string `json:"token"` + TokenID int `json:"token_id"` + ParentID string `json:"parent_id"` + Name string `json:"name"` + Path string `json:"path"` } func (t *Token) TTL() time.Duration { @@ -56,7 +58,7 @@ func (t *Token) SetExpiresAt(expiresAt *time.Time) { t.ExpiresAt = expiresAt } func (t *Token) SetConfigName(name string) { t.ConfigName = name } func (t *Token) SetRoleName(name string) { t.RoleName = name } func (t *Token) SetGitlabRevokesToken(b bool) { t.GitlabRevokesToken = b } -func (t *Token) Type() TokenType { return t.TokenType } +func (t *Token) Type() token.TokenType { return t.TokenType } func (t *Token) Internal() map[string]any { return map[string]any{ diff --git a/with_admin_user_pat_gitlab_revokes_token_test.go b/with_admin_user_pat_gitlab_revokes_token_test.go index 32079fc..7e441e4 100644 --- a/with_admin_user_pat_gitlab_revokes_token_test.go +++ b/with_admin_user_pat_gitlab_revokes_token_test.go @@ -16,6 +16,7 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + token2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestWithAdminUser_PAT_AdminUser_GitlabRevokesToken(t *testing.T) { @@ -53,8 +54,8 @@ func TestWithAdminUser_PAT_AdminUser_GitlabRevokesToken(t *testing.T) { Path: fmt.Sprintf("%s/normal-user", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "normal-user", - "name": gitlab.TokenTypePersonal.String(), - "token_type": gitlab.TokenTypePersonal.String(), + "name": token2.TokenTypePersonal.String(), + "token_type": token2.TokenTypePersonal.String(), "ttl": time.Hour * 120, "gitlab_revokes_token": strconv.FormatBool(true), "scopes": strings.Join( diff --git a/with_admin_user_pat_vault_revokes_token_test.go b/with_admin_user_pat_vault_revokes_token_test.go index d6046f5..a743012 100644 --- a/with_admin_user_pat_vault_revokes_token_test.go +++ b/with_admin_user_pat_vault_revokes_token_test.go @@ -16,6 +16,7 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + token2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestWithAdminUser_PAT_AdminUser_VaultRevokesToken(t *testing.T) { @@ -54,8 +55,8 @@ func TestWithAdminUser_PAT_AdminUser_VaultRevokesToken(t *testing.T) { Path: fmt.Sprintf("%s/admin-user", gitlab.PathRoleStorage), Data: map[string]any{ "path": "admin-user", - "name": gitlab.TokenTypePersonal.String(), - "token_type": gitlab.TokenTypePersonal.String(), + "name": token2.TokenTypePersonal.String(), + "token_type": token2.TokenTypePersonal.String(), "scopes": strings.Join( []string{ gitlab.TokenScopeReadApi.String(), diff --git a/with_group_deploy_token_test.go b/with_group_deploy_token_test.go index f76bbd5..0b07e3a 100644 --- a/with_group_deploy_token_test.go +++ b/with_group_deploy_token_test.go @@ -14,6 +14,7 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + token2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestWithGroupDeployToken(t *testing.T) { @@ -51,8 +52,8 @@ func TestWithGroupDeployToken(t *testing.T) { Path: fmt.Sprintf("%s/role", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "example", - "name": gitlab.TokenTypeGroupDeploy.String(), - "token_type": gitlab.TokenTypeGroupDeploy.String(), + "name": token2.TokenTypeGroupDeploy.String(), + "token_type": token2.TokenTypeGroupDeploy.String(), "gitlab_revokes_token": strconv.FormatBool(false), "ttl": 120 * time.Hour, "scopes": []string{gitlab.TokenScopeReadRepository.String()}, diff --git a/with_normal_user_gat_test.go b/with_normal_user_gat_test.go index 5c131cb..7fedfe8 100644 --- a/with_normal_user_gat_test.go +++ b/with_normal_user_gat_test.go @@ -16,6 +16,7 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + token2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestWithNormalUser_GAT(t *testing.T) { @@ -53,7 +54,7 @@ func TestWithNormalUser_GAT(t *testing.T) { Data: map[string]any{ "path": "example", "name": `gat-token`, - "token_type": gitlab.TokenTypeGroup.String(), + "token_type": token2.TokenTypeGroup.String(), "ttl": time.Hour * 120, "gitlab_revokes_token": strconv.FormatBool(false), "access_level": gitlab.AccessLevelMaintainerPermissions.String(), diff --git a/with_normal_user_personal_at_fails_test.go b/with_normal_user_personal_at_fails_test.go index f7d5433..a4834f2 100644 --- a/with_normal_user_personal_at_fails_test.go +++ b/with_normal_user_personal_at_fails_test.go @@ -14,6 +14,7 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestWithNormalUser_PersonalAT_Fails(t *testing.T) { @@ -47,8 +48,8 @@ func TestWithNormalUser_PersonalAT_Fails(t *testing.T) { Path: fmt.Sprintf("%s/normal-user", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "normal-user", - "name": gitlab.TokenTypePersonal.String(), - "token_type": gitlab.TokenTypePersonal.String(), + "name": token.TokenTypePersonal.String(), + "token_type": token.TokenTypePersonal.String(), "ttl": time.Hour * 120, "gitlab_revokes_token": strconv.FormatBool(true), "scopes": strings.Join( diff --git a/with_normal_user_project_at_test.go b/with_normal_user_project_at_test.go index 683f5ac..4c9510e 100644 --- a/with_normal_user_project_at_test.go +++ b/with_normal_user_project_at_test.go @@ -16,6 +16,7 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + tok "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestWithNormalUser_ProjectAT(t *testing.T) { @@ -53,8 +54,8 @@ func TestWithNormalUser_ProjectAT(t *testing.T) { Path: fmt.Sprintf("%s/pat", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "example/example", - "name": gitlab.TokenTypeProject.String(), - "token_type": gitlab.TokenTypeProject.String(), + "name": tok.TokenTypeProject.String(), + "token_type": tok.TokenTypeProject.String(), "ttl": time.Hour * 120, "gitlab_revokes_token": strconv.FormatBool(false), "access_level": gitlab.AccessLevelMaintainerPermissions.String(), diff --git a/with_pipeline_project_trigger_token_test.go b/with_pipeline_project_trigger_token_test.go index 16cf515..212c3d1 100644 --- a/with_pipeline_project_trigger_token_test.go +++ b/with_pipeline_project_trigger_token_test.go @@ -13,6 +13,7 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + token2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestWithPipelineProjectTriggerAccessToken(t *testing.T) { @@ -50,8 +51,8 @@ func TestWithPipelineProjectTriggerAccessToken(t *testing.T) { Path: fmt.Sprintf("%s/pptat", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "example/example", - "name": gitlab.TokenTypePipelineProjectTrigger.String(), - "token_type": gitlab.TokenTypePipelineProjectTrigger.String(), + "name": token2.TokenTypePipelineProjectTrigger.String(), + "token_type": token2.TokenTypePipelineProjectTrigger.String(), "gitlab_revokes_token": strconv.FormatBool(false), }, }) diff --git a/with_project_deploy_token_test.go b/with_project_deploy_token_test.go index 41608a5..e3e0c88 100644 --- a/with_project_deploy_token_test.go +++ b/with_project_deploy_token_test.go @@ -14,6 +14,7 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + token2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestWithProjectDeployToken(t *testing.T) { @@ -51,8 +52,8 @@ func TestWithProjectDeployToken(t *testing.T) { Path: fmt.Sprintf("%s/role", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "example/example", - "name": gitlab.TokenTypeProjectDeploy.String(), - "token_type": gitlab.TokenTypeProjectDeploy.String(), + "name": token2.TokenTypeProjectDeploy.String(), + "token_type": token2.TokenTypeProjectDeploy.String(), "gitlab_revokes_token": strconv.FormatBool(false), "ttl": 120 * time.Hour, "scopes": []string{gitlab.TokenScopeReadRepository.String()}, diff --git a/with_service_account_fail_test.go b/with_service_account_fail_test.go index 62da413..df31974 100644 --- a/with_service_account_fail_test.go +++ b/with_service_account_fail_test.go @@ -12,6 +12,7 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestWithServiceAccountUserFail(t *testing.T) { @@ -57,7 +58,7 @@ func TestWithServiceAccountUserFail(t *testing.T) { Data: map[string]any{ "path": usr.Username, "name": fmt.Sprintf(`user-service-account-%s`, usr.Username), - "token_type": gitlab.TokenTypeUserServiceAccount.String(), + "token_type": token.TokenTypeUserServiceAccount.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": gitlab.ValidUserServiceAccountTokenScopes, "gitlab_revokes_token": false, diff --git a/with_service_account_group_test.go b/with_service_account_group_test.go index 6e99044..75421ca 100644 --- a/with_service_account_group_test.go +++ b/with_service_account_group_test.go @@ -14,6 +14,7 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + token2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestWithServiceAccountGroup(t *testing.T) { @@ -62,7 +63,7 @@ func TestWithServiceAccountGroup(t *testing.T) { Data: map[string]any{ "path": fmt.Sprintf("%s/%s", gid, sa.UserName), "name": `vault-generated-{{ .token_type }}-token`, - "token_type": gitlab.TokenTypeGroupServiceAccount.String(), + "token_type": token2.TokenTypeGroupServiceAccount.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": gitlab.ValidGroupServiceAccountTokenScopes, "gitlab_revokes_token": false, diff --git a/with_service_account_user_test.go b/with_service_account_user_test.go index a7fb6cc..6bd552e 100644 --- a/with_service_account_user_test.go +++ b/with_service_account_user_test.go @@ -13,6 +13,7 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + token2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestWithServiceAccountUser(t *testing.T) { @@ -60,7 +61,7 @@ func TestWithServiceAccountUser(t *testing.T) { Data: map[string]any{ "path": usr.Username, "name": `vault-generated-{{ .token_type }}-token`, - "token_type": gitlab.TokenTypeUserServiceAccount.String(), + "token_type": token2.TokenTypeUserServiceAccount.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": gitlab.ValidUserServiceAccountTokenScopes, "gitlab_revokes_token": false, From 59b3f512a6424461ddd3878898610e7757e1ad7b Mon Sep 17 00:00:00 2001 From: Ilija Matoski Date: Mon, 16 Jun 2025 17:39:32 +0200 Subject: [PATCH 06/17] rename TokenType to Type under token pkg --- entry_role.go | 18 +++---- gitlab_client.go | 20 ++++---- gitlab_client_test.go | 8 ++-- helpers_test.go | 42 ++++++++-------- internal/token/type.go | 48 +++++++++---------- internal/token/type_test.go | 44 ++++++++--------- name_tpl_rand_string_test.go | 2 +- name_tpl_test.go | 8 ++-- name_tpl_unix_timestamp_test.go | 2 +- path_role.go | 26 +++++----- path_role_deploy_tokens_test.go | 6 +-- ...ole_pipeline_project_trigger_token_test.go | 6 +-- path_role_test.go | 46 +++++++++--------- path_role_ttl_test.go | 6 +-- path_token_role.go | 16 +++---- path_token_role_multiple_config_test.go | 16 +++---- path_token_role_test.go | 26 +++++----- secret_access_tokens.go | 20 ++++---- token.go | 26 +++++----- ...dmin_user_pat_gitlab_revokes_token_test.go | 4 +- ...admin_user_pat_vault_revokes_token_test.go | 4 +- with_group_deploy_token_test.go | 4 +- with_normal_user_gat_test.go | 2 +- with_normal_user_personal_at_fails_test.go | 4 +- with_normal_user_project_at_test.go | 4 +- with_pipeline_project_trigger_token_test.go | 4 +- with_project_deploy_token_test.go | 4 +- with_service_account_fail_test.go | 2 +- with_service_account_group_test.go | 2 +- with_service_account_user_test.go | 2 +- 30 files changed, 211 insertions(+), 211 deletions(-) diff --git a/entry_role.go b/entry_role.go index aedfd45..b97f2f1 100644 --- a/entry_role.go +++ b/entry_role.go @@ -11,15 +11,15 @@ import ( ) type EntryRole struct { - RoleName string `json:"role_name" structs:"role_name" mapstructure:"role_name"` - TTL time.Duration `json:"ttl" structs:"ttl" mapstructure:"ttl"` - Path string `json:"path" structs:"path" mapstructure:"path"` - Name string `json:"name" structs:"name" mapstructure:"name"` - Scopes []string `json:"scopes" structs:"scopes" mapstructure:"scopes"` - AccessLevel AccessLevel `json:"access_level" structs:"access_level" mapstructure:"access_level,omitempty"` - TokenType token.TokenType `json:"token_type" structs:"token_type" mapstructure:"token_type"` - GitlabRevokesTokens bool `json:"gitlab_revokes_token" structs:"gitlab_revokes_token" mapstructure:"gitlab_revokes_token"` - ConfigName string `json:"config_name" structs:"config_name" mapstructure:"config_name"` + RoleName string `json:"role_name" structs:"role_name" mapstructure:"role_name"` + TTL time.Duration `json:"ttl" structs:"ttl" mapstructure:"ttl"` + Path string `json:"path" structs:"path" mapstructure:"path"` + Name string `json:"name" structs:"name" mapstructure:"name"` + Scopes []string `json:"scopes" structs:"scopes" mapstructure:"scopes"` + AccessLevel AccessLevel `json:"access_level" structs:"access_level" mapstructure:"access_level,omitempty"` + TokenType token.Type `json:"token_type" structs:"token_type" mapstructure:"token_type"` + GitlabRevokesTokens bool `json:"gitlab_revokes_token" structs:"gitlab_revokes_token" mapstructure:"gitlab_revokes_token"` + ConfigName string `json:"config_name" structs:"config_name" mapstructure:"config_name"` } func (e EntryRole) LogicalResponseData() map[string]any { diff --git a/gitlab_client.go b/gitlab_client.go index e3d402e..b1428da 100644 --- a/gitlab_client.go +++ b/gitlab_client.go @@ -96,7 +96,7 @@ func (gc *gitlabClient) CreateGroupDeployToken(ctx context.Context, path string, Path: path, Name: name, Token: dt.Token, - TokenType: t.TokenTypeGroupDeploy, + TokenType: t.TypeGroupDeploy, CreatedAt: g.Ptr(time.Now()), }, Scopes: scopes, @@ -129,7 +129,7 @@ func (gc *gitlabClient) CreateProjectDeployToken(ctx context.Context, path strin Path: path, Name: name, Token: dt.Token, - TokenType: t.TokenTypeProjectDeploy, + TokenType: t.TypeProjectDeploy, CreatedAt: g.Ptr(time.Now()), }, Scopes: scopes, @@ -185,7 +185,7 @@ func (gc *gitlabClient) CreatePipelineProjectTriggerAccessToken(ctx context.Cont Path: path, Name: name, Token: pt.Token, - TokenType: t.TokenTypePipelineProjectTrigger, + TokenType: t.TypePipelineProjectTrigger, CreatedAt: g.Ptr(time.Now()), ExpiresAt: expiresAt, }, @@ -248,7 +248,7 @@ func (gc *gitlabClient) CreateGroupServiceAccountAccessToken(ctx context.Context Path: path, Name: name, Token: at.Token, - TokenType: t.TokenTypeGroupServiceAccount, + TokenType: t.TypeGroupServiceAccount, CreatedAt: at.CreatedAt, ExpiresAt: (*time.Time)(at.ExpiresAt), }, @@ -275,7 +275,7 @@ func (gc *gitlabClient) CreateUserServiceAccountAccessToken(ctx context.Context, Path: etp.Path, Name: etp.Name, Token: etp.Token.Token, - TokenType: t.TokenTypeUserServiceAccount, + TokenType: t.TypeUserServiceAccount, CreatedAt: etp.CreatedAt, ExpiresAt: etp.ExpiresAt, }, @@ -332,7 +332,7 @@ func (gc *gitlabClient) CurrentTokenInfo(ctx context.Context) (et *TokenConfig, TokenID: pat.ID, Name: pat.Name, Token: pat.Token, - TokenType: t.TokenTypePersonal, + TokenType: t.TypePersonal, CreatedAt: pat.CreatedAt, ExpiresAt: (*time.Time)(pat.ExpiresAt), }, @@ -388,7 +388,7 @@ func (gc *gitlabClient) RotateCurrentToken(ctx context.Context) (token *TokenCon Path: usr.Username, Name: pat.Name, Token: pat.Token, - TokenType: t.TokenTypePersonal, + TokenType: t.TypePersonal, CreatedAt: pat.CreatedAt, ExpiresAt: (*time.Time)(pat.ExpiresAt), }, @@ -448,7 +448,7 @@ func (gc *gitlabClient) CreatePersonalAccessToken(ctx context.Context, username Path: username, Name: name, Token: at.Token, - TokenType: t.TokenTypePersonal, + TokenType: t.TypePersonal, CreatedAt: at.CreatedAt, ExpiresAt: (*time.Time)(at.ExpiresAt), }, @@ -481,7 +481,7 @@ func (gc *gitlabClient) CreateGroupAccessToken(ctx context.Context, groupId stri Path: groupId, Name: name, Token: at.Token, - TokenType: t.TokenTypeGroup, + TokenType: t.TypeGroup, CreatedAt: at.CreatedAt, ExpiresAt: (*time.Time)(at.ExpiresAt), }, @@ -514,7 +514,7 @@ func (gc *gitlabClient) CreateProjectAccessToken(ctx context.Context, projectId Path: projectId, Name: name, Token: at.Token, - TokenType: t.TokenTypeProject, + TokenType: t.TypeProject, CreatedAt: at.CreatedAt, ExpiresAt: (*time.Time)(at.ExpiresAt), }, diff --git a/gitlab_client_test.go b/gitlab_client_test.go index a210c89..e0bed6a 100644 --- a/gitlab_client_test.go +++ b/gitlab_client_test.go @@ -217,7 +217,7 @@ func TestGitlabClient_CurrentTokenInfo(t *testing.T) { token, err := client.CurrentTokenInfo(ctx) require.NoError(t, err) require.NotNil(t, token) - assert.EqualValues(t, token2.TokenTypePersonal, token.TokenType) + assert.EqualValues(t, token2.TypePersonal, token.TokenType) } func TestGitlabClient_Metadata(t *testing.T) { @@ -262,7 +262,7 @@ func TestGitlabClient_CreateAccessToken_And_Revoke(t *testing.T) { ) require.NoError(t, err) require.NotNil(t, gatToken) - require.EqualValues(t, token2.TokenTypeGroup, gatToken.TokenType) + require.EqualValues(t, token2.TypeGroup, gatToken.TokenType) require.NotEmpty(t, gatToken.Token) require.NoError(t, client.RevokeGroupAccessToken(ctx, gatToken.TokenID, "example")) @@ -276,7 +276,7 @@ func TestGitlabClient_CreateAccessToken_And_Revoke(t *testing.T) { ) require.NoError(t, err) require.NotNil(t, prjatToken) - require.EqualValues(t, token2.TokenTypeProject, prjatToken.TokenType) + require.EqualValues(t, token2.TypeProject, prjatToken.TokenType) require.NotEmpty(t, prjatToken.Token) require.NoError(t, client.RevokeProjectAccessToken(ctx, prjatToken.TokenID, "example/example")) @@ -290,7 +290,7 @@ func TestGitlabClient_CreateAccessToken_And_Revoke(t *testing.T) { ) require.NoError(t, err) require.NotNil(t, patToken) - require.EqualValues(t, token2.TokenTypePersonal, patToken.TokenType) + require.EqualValues(t, token2.TypePersonal, patToken.TokenType) require.NotEmpty(t, patToken.Token) require.NoError(t, client.RevokePersonalAccessToken(ctx, patToken.TokenID)) } diff --git a/helpers_test.go b/helpers_test.go index a3d12c9..46e4736 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -227,7 +227,7 @@ func (i *inMemoryClient) CreateProjectDeployToken(ctx context.Context, path stri } i.internalCounter++ var tokenId = i.internalCounter - key := fmt.Sprintf("%s_%v_%v", t.TokenTypeProjectDeploy.String(), projectId, tokenId) + key := fmt.Sprintf("%s_%v_%v", t.TypeProjectDeploy.String(), projectId, tokenId) var entryToken = &gitlab.TokenProjectDeploy{ TokenWithScopes: gitlab.TokenWithScopes{ Token: gitlab.Token{ @@ -236,7 +236,7 @@ func (i *inMemoryClient) CreateProjectDeployToken(ctx context.Context, path stri Path: path, Name: name, Token: fmt.Sprintf("glpat-%s", uuid.New().String()), - TokenType: t.TokenTypeProjectDeploy, + TokenType: t.TypeProjectDeploy, ExpiresAt: expiresAt, CreatedAt: g.Ptr(time.Now())}, Scopes: scopes, @@ -255,7 +255,7 @@ func (i *inMemoryClient) CreateGroupDeployToken(ctx context.Context, path string } i.internalCounter++ var tokenId = i.internalCounter - key := fmt.Sprintf("%s_%v_%v", t.TokenTypeGroupDeploy.String(), groupId, tokenId) + key := fmt.Sprintf("%s_%v_%v", t.TypeGroupDeploy.String(), groupId, tokenId) var entryToken = &gitlab.TokenGroupDeploy{ TokenWithScopes: gitlab.TokenWithScopes{ Token: gitlab.Token{ @@ -264,7 +264,7 @@ func (i *inMemoryClient) CreateGroupDeployToken(ctx context.Context, path string Path: path, Name: name, Token: fmt.Sprintf("glpat-%s", uuid.New().String()), - TokenType: t.TokenTypeGroupDeploy, + TokenType: t.TypeGroupDeploy, ExpiresAt: expiresAt, CreatedAt: g.Ptr(time.Now()), }, @@ -282,7 +282,7 @@ func (i *inMemoryClient) RevokeProjectDeployToken(ctx context.Context, projectId if i.revokeProjectDeployTokenError { return errors.New("revoke project deploy token error") } - key := fmt.Sprintf("%s_%v_%v", t.TokenTypeProjectDeploy.String(), projectId, deployTokenId) + key := fmt.Sprintf("%s_%v_%v", t.TypeProjectDeploy.String(), projectId, deployTokenId) delete(i.accessTokens, key) return nil } @@ -293,7 +293,7 @@ func (i *inMemoryClient) RevokeGroupDeployToken(ctx context.Context, groupId, de if i.revokeGroupDeployTokenError { return errors.New("revoke group deploy token error") } - key := fmt.Sprintf("%s_%v_%v", t.TokenTypeGroupDeploy.String(), groupId, deployTokenId) + key := fmt.Sprintf("%s_%v_%v", t.TypeGroupDeploy.String(), groupId, deployTokenId) delete(i.accessTokens, key) return nil } @@ -317,7 +317,7 @@ func (i *inMemoryClient) CreatePipelineProjectTriggerAccessToken(ctx context.Con } i.internalCounter++ var tokenId = i.internalCounter - key := fmt.Sprintf("%s_%v_%v", t.TokenTypePipelineProjectTrigger.String(), projectId, tokenId) + key := fmt.Sprintf("%s_%v_%v", t.TypePipelineProjectTrigger.String(), projectId, tokenId) var entryToken = &gitlab.TokenPipelineProjectTrigger{ Token: gitlab.Token{ TokenID: tokenId, @@ -325,7 +325,7 @@ func (i *inMemoryClient) CreatePipelineProjectTriggerAccessToken(ctx context.Con Path: strconv.Itoa(projectId), Name: name, Token: fmt.Sprintf("glptt-%s", uuid.New().String()), - TokenType: t.TokenTypePipelineProjectTrigger, + TokenType: t.TypePipelineProjectTrigger, ExpiresAt: expiresAt, CreatedAt: g.Ptr(time.Now()), }, @@ -340,7 +340,7 @@ func (i *inMemoryClient) RevokePipelineProjectTriggerAccessToken(ctx context.Con if i.revokePipelineProjectTriggerAccessTokenError { return fmt.Errorf("RevokePipelineProjectTriggerAccessToken") } - key := fmt.Sprintf("%s_%v_%v", t.TokenTypePipelineProjectTrigger.String(), projectId, tokenId) + key := fmt.Sprintf("%s_%v_%v", t.TypePipelineProjectTrigger.String(), projectId, tokenId) delete(i.accessTokens, key) return nil } @@ -383,7 +383,7 @@ func (i *inMemoryClient) CreateUserServiceAccountAccessToken(ctx context.Context Token: gitlab.Token{ CreatedAt: cpat.CreatedAt, ExpiresAt: cpat.ExpiresAt, - TokenType: t.TokenTypeUserServiceAccount, + TokenType: t.TypeUserServiceAccount, Token: cpat.Token.Token, TokenID: cpat.TokenID, ParentID: cpat.ParentID, @@ -404,7 +404,7 @@ func (i *inMemoryClient) RevokeUserServiceAccountAccessToken(ctx context.Context if i.revokeUserServiceAccountPersonalAccessTokenError { return errors.New("RevokeServiceAccountPersonalAccessToken") } - delete(i.accessTokens, fmt.Sprintf("%s_%v", t.TokenTypeUserServiceAccount.String(), token)) + delete(i.accessTokens, fmt.Sprintf("%s_%v", t.TypeUserServiceAccount.String(), token)) return nil } @@ -414,7 +414,7 @@ func (i *inMemoryClient) RevokeGroupServiceAccountAccessToken(ctx context.Contex if i.revokeGroupServiceAccountPersonalAccessTokenError { return errors.New("RevokeServiceAccountPersonalAccessToken") } - delete(i.accessTokens, fmt.Sprintf("%s_%v", t.TokenTypeGroupServiceAccount.String(), token)) + delete(i.accessTokens, fmt.Sprintf("%s_%v", t.TypeGroupServiceAccount.String(), token)) return nil } @@ -455,7 +455,7 @@ func (i *inMemoryClient) CreatePersonalAccessToken(ctx context.Context, username Path: username, Name: name, Token: fmt.Sprintf("glpat-%s", uuid.New().String()), - TokenType: t.TokenTypePersonal, + TokenType: t.TypePersonal, CreatedAt: g.Ptr(time.Now()), ExpiresAt: &expiresAt, }, @@ -463,7 +463,7 @@ func (i *inMemoryClient) CreatePersonalAccessToken(ctx context.Context, username }, UserID: userId, } - i.accessTokens[fmt.Sprintf("%s_%v", t.TokenTypePersonal.String(), tokenId)] = entryToken + i.accessTokens[fmt.Sprintf("%s_%v", t.TypePersonal.String(), tokenId)] = entryToken return entryToken, nil } @@ -483,7 +483,7 @@ func (i *inMemoryClient) CreateGroupAccessToken(ctx context.Context, groupId str Path: groupId, Name: name, Token: fmt.Sprintf("glgat-%s", uuid.New().String()), - TokenType: t.TokenTypeGroup, + TokenType: t.TypeGroup, CreatedAt: g.Ptr(time.Now()), ExpiresAt: &expiresAt, }, @@ -491,7 +491,7 @@ func (i *inMemoryClient) CreateGroupAccessToken(ctx context.Context, groupId str AccessLevel: accessLevel, }, } - i.accessTokens[fmt.Sprintf("%s_%v", t.TokenTypeGroup.String(), tokenId)] = entryToken + i.accessTokens[fmt.Sprintf("%s_%v", t.TypeGroup.String(), tokenId)] = entryToken return entryToken, nil } @@ -507,7 +507,7 @@ func (i *inMemoryClient) CreateProjectAccessToken(ctx context.Context, projectId TokenWithScopesAndAccessLevel: gitlab.TokenWithScopesAndAccessLevel{ Token: gitlab.Token{ Token: fmt.Sprintf("glpat-%s", uuid.New().String()), - TokenType: t.TokenTypeProject, + TokenType: t.TypeProject, CreatedAt: g.Ptr(time.Now()), ExpiresAt: &expiresAt, TokenID: tokenId, @@ -519,7 +519,7 @@ func (i *inMemoryClient) CreateProjectAccessToken(ctx context.Context, projectId AccessLevel: accessLevel, }, } - i.accessTokens[fmt.Sprintf("%s_%v", t.TokenTypeProject.String(), tokenId)] = entryToken + i.accessTokens[fmt.Sprintf("%s_%v", t.TypeProject.String(), tokenId)] = entryToken return entryToken, nil } @@ -529,7 +529,7 @@ func (i *inMemoryClient) RevokePersonalAccessToken(ctx context.Context, tokenId if i.personalAccessTokenRevokeError { return fmt.Errorf("RevokePersonalAccessToken") } - delete(i.accessTokens, fmt.Sprintf("%s_%v", t.TokenTypePersonal.String(), tokenId)) + delete(i.accessTokens, fmt.Sprintf("%s_%v", t.TypePersonal.String(), tokenId)) return nil } @@ -539,7 +539,7 @@ func (i *inMemoryClient) RevokeProjectAccessToken(ctx context.Context, tokenId i if i.projectAccessTokenRevokeError { return fmt.Errorf("RevokeProjectAccessToken") } - delete(i.accessTokens, fmt.Sprintf("%s_%v", t.TokenTypeProject.String(), tokenId)) + delete(i.accessTokens, fmt.Sprintf("%s_%v", t.TypeProject.String(), tokenId)) return nil } @@ -549,7 +549,7 @@ func (i *inMemoryClient) RevokeGroupAccessToken(ctx context.Context, tokenId int if i.groupAccessTokenRevokeError { return fmt.Errorf("RevokeGroupAccessToken") } - delete(i.accessTokens, fmt.Sprintf("%s_%v", t.TokenTypeGroup.String(), tokenId)) + delete(i.accessTokens, fmt.Sprintf("%s_%v", t.TypeGroup.String(), tokenId)) return nil } diff --git a/internal/token/type.go b/internal/token/type.go index 142d995..421a9c5 100644 --- a/internal/token/type.go +++ b/internal/token/type.go @@ -6,47 +6,47 @@ import ( "slices" ) -type TokenType string +type Type string const ( - TokenTypePersonal = TokenType("personal") - TokenTypeProject = TokenType("project") - TokenTypeGroup = TokenType("group") - TokenTypeUserServiceAccount = TokenType("user-service-account") - TokenTypeGroupServiceAccount = TokenType("group-service-account") - TokenTypePipelineProjectTrigger = TokenType("pipeline-project-trigger") - TokenTypeProjectDeploy = TokenType("project-deploy") - TokenTypeGroupDeploy = TokenType("group-deploy") - - TokenTypeUnknown = TokenType("") + TypePersonal = Type("personal") + TypeProject = Type("project") + TypeGroup = Type("group") + TypeUserServiceAccount = Type("user-service-account") + TypeGroupServiceAccount = Type("group-service-account") + TypePipelineProjectTrigger = Type("pipeline-project-trigger") + TypeProjectDeploy = Type("project-deploy") + TypeGroupDeploy = Type("group-deploy") + + TypeUnknown = Type("") ) var ( ErrUnknownTokenType = errors.New("unknown token type") ValidTokenTypes = []string{ - TokenTypePersonal.String(), - TokenTypeProject.String(), - TokenTypeGroup.String(), - TokenTypeUserServiceAccount.String(), - TokenTypeGroupServiceAccount.String(), - TokenTypePipelineProjectTrigger.String(), - TokenTypeProjectDeploy.String(), - TokenTypeGroupDeploy.String(), + TypePersonal.String(), + TypeProject.String(), + TypeGroup.String(), + TypeUserServiceAccount.String(), + TypeGroupServiceAccount.String(), + TypePipelineProjectTrigger.String(), + TypeProjectDeploy.String(), + TypeGroupDeploy.String(), } ) -func (i TokenType) String() string { +func (i Type) String() string { return string(i) } -func (i TokenType) Value() string { +func (i Type) Value() string { return i.String() } -func TokenTypeParse(value string) (TokenType, error) { +func TypeParse(value string) (Type, error) { if slices.Contains(ValidTokenTypes, value) { - return TokenType(value), nil + return Type(value), nil } - return TokenTypeUnknown, fmt.Errorf("failed to parse '%s': %w", value, ErrUnknownTokenType) + return TypeUnknown, fmt.Errorf("failed to parse '%s': %w", value, ErrUnknownTokenType) } diff --git a/internal/token/type_test.go b/internal/token/type_test.go index 19b9aff..414bb32 100644 --- a/internal/token/type_test.go +++ b/internal/token/type_test.go @@ -7,54 +7,54 @@ import ( "github.com/stretchr/testify/assert" - gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestTokenType(t *testing.T) { var tests = []struct { - expected gitlab.TokenType + expected token.Type input string err bool }{ { - expected: gitlab.TokenTypePersonal, - input: gitlab.TokenTypePersonal.String(), + expected: token.TypePersonal, + input: token.TypePersonal.String(), }, { - expected: gitlab.TokenTypeGroup, - input: gitlab.TokenTypeGroup.String(), + expected: token.TypeGroup, + input: token.TypeGroup.String(), }, { - expected: gitlab.TokenTypeProject, - input: gitlab.TokenTypeProject.String(), + expected: token.TypeProject, + input: token.TypeProject.String(), }, { - expected: gitlab.TokenTypeUserServiceAccount, - input: gitlab.TokenTypeUserServiceAccount.String(), + expected: token.TypeUserServiceAccount, + input: token.TypeUserServiceAccount.String(), }, { - expected: gitlab.TokenTypeGroupServiceAccount, - input: gitlab.TokenTypeGroupServiceAccount.String(), + expected: token.TypeGroupServiceAccount, + input: token.TypeGroupServiceAccount.String(), }, { - expected: gitlab.TokenTypePipelineProjectTrigger, - input: gitlab.TokenTypePipelineProjectTrigger.String(), + expected: token.TypePipelineProjectTrigger, + input: token.TypePipelineProjectTrigger.String(), }, { - expected: gitlab.TokenTypeProjectDeploy, - input: gitlab.TokenTypeProjectDeploy.String(), + expected: token.TypeProjectDeploy, + input: token.TypeProjectDeploy.String(), }, { - expected: gitlab.TokenTypeGroupDeploy, - input: gitlab.TokenTypeGroupDeploy.String(), + expected: token.TypeGroupDeploy, + input: token.TypeGroupDeploy.String(), }, { - expected: gitlab.TokenTypeUnknown, + expected: token.TypeUnknown, input: "unknown", err: true, }, { - expected: gitlab.TokenTypeUnknown, + expected: token.TypeUnknown, input: "unknown", err: true, }, @@ -62,11 +62,11 @@ func TestTokenType(t *testing.T) { for _, test := range tests { t.Logf("assert parse(%s) = %s (err: %v)", test.input, test.expected, test.err) - val, err := gitlab.TokenTypeParse(test.input) + val, err := token.TypeParse(test.input) assert.EqualValues(t, test.expected, val) assert.EqualValues(t, test.expected.Value(), test.expected.String()) if test.err { - assert.ErrorIs(t, err, gitlab.ErrUnknownTokenType) + assert.ErrorIs(t, err, token.ErrUnknownTokenType) } else { assert.NoError(t, err) } diff --git a/name_tpl_rand_string_test.go b/name_tpl_rand_string_test.go index 86cc711..db2d49e 100644 --- a/name_tpl_rand_string_test.go +++ b/name_tpl_rand_string_test.go @@ -21,7 +21,7 @@ func TestTokenNameGenerator_RandString(t *testing.T) { Name: "{{ randHexString 8 }}", Scopes: []string{g.TokenScopeApi.String()}, AccessLevel: g.AccessLevelNoPermissions, - TokenType: token.TokenTypePersonal, + TokenType: token.TypePersonal, GitlabRevokesTokens: false, }, ) diff --git a/name_tpl_test.go b/name_tpl_test.go index cfa64ff..e56ccaf 100644 --- a/name_tpl_test.go +++ b/name_tpl_test.go @@ -30,7 +30,7 @@ func TestTokenNameGenerator(t *testing.T) { Name: "{{ .role_name", Scopes: []string{g.TokenScopeApi.String()}, AccessLevel: g.AccessLevelNoPermissions, - TokenType: token.TokenTypePersonal, + TokenType: token.TypePersonal, GitlabRevokesTokens: true, }, "", @@ -46,7 +46,7 @@ func TestTokenNameGenerator(t *testing.T) { Name: "{{ .role_name }}-{{ .token_type }}-access-token-{{ yesNoBool .gitlab_revokes_token }}", Scopes: []string{g.TokenScopeApi.String()}, AccessLevel: g.AccessLevelNoPermissions, - TokenType: token.TokenTypePersonal, + TokenType: token.TypePersonal, GitlabRevokesTokens: true, }, "test-personal-access-token-yes", @@ -62,7 +62,7 @@ func TestTokenNameGenerator(t *testing.T) { Name: "{{ .role_name }}-{{ .token_type }}-{{ stringsJoin .scopes \"-\" }}-{{ yesNoBool .gitlab_revokes_token }}", Scopes: []string{g.TokenScopeApi.String(), g.TokenScopeSudo.String()}, AccessLevel: g.AccessLevelNoPermissions, - TokenType: token.TokenTypePersonal, + TokenType: token.TypePersonal, GitlabRevokesTokens: false, }, "test-personal-api-sudo-no", @@ -78,7 +78,7 @@ func TestTokenNameGenerator(t *testing.T) { Name: "{{ .role_name }}-{{ .token_type }}-{{ timeNowFormat \"2006-01\" }}", Scopes: []string{g.TokenScopeApi.String(), g.TokenScopeSudo.String()}, AccessLevel: g.AccessLevelNoPermissions, - TokenType: token.TokenTypePersonal, + TokenType: token.TypePersonal, GitlabRevokesTokens: false, }, fmt.Sprintf("test-personal-%d-%02d", time.Now().UTC().Year(), time.Now().UTC().Month()), diff --git a/name_tpl_unix_timestamp_test.go b/name_tpl_unix_timestamp_test.go index 7a133b9..28eca4d 100644 --- a/name_tpl_unix_timestamp_test.go +++ b/name_tpl_unix_timestamp_test.go @@ -23,7 +23,7 @@ func TestTokenNameGenerator_UnixTimeStamp(t *testing.T) { Name: "{{ .unix_timestamp_utc }}", Scopes: []string{g.TokenScopeApi.String()}, AccessLevel: g.AccessLevelNoPermissions, - TokenType: token.TokenTypePersonal, + TokenType: token.TypePersonal, GitlabRevokesTokens: false, }, ) diff --git a/path_role.go b/path_role.go index 3951406..7719793 100644 --- a/path_role.go +++ b/path_role.go @@ -204,7 +204,7 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data var config *EntryConfig var err error var warnings []string - var tokenType token.TokenType + var tokenType token.Type var accessLevel AccessLevel var configName = cmp.Or(data.Get("config_name").(string), TypeConfigDefault) @@ -219,7 +219,7 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data return logical.ErrorResponse(errs.ErrBackendNotConfigured.Error()), nil } - tokenType, _ = token.TokenTypeParse(data.Get("token_type").(string)) + tokenType, _ = token.TypeParse(data.Get("token_type").(string)) accessLevel, _ = AccessLevelParse(data.Get("access_level").(string)) var role = EntryRole{ @@ -251,42 +251,42 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data var skipFields []string switch tokenType { - case token.TokenTypePersonal: + case token.TypePersonal: validAccessLevels = ValidPersonalAccessLevels validScopes = ValidPersonalTokenScopes noEmptyScopes = false skipFields = []string{"config_name", "access_level"} - case token.TokenTypeGroup: + case token.TypeGroup: validAccessLevels = ValidGroupAccessLevels validScopes = ValidGroupTokenScopes noEmptyScopes = false skipFields = []string{"config_name"} - case token.TokenTypeProject: + case token.TypeProject: validAccessLevels = ValidProjectAccessLevels validScopes = ValidProjectTokenScopes noEmptyScopes = false skipFields = []string{"config_name"} - case token.TokenTypeUserServiceAccount: + case token.TypeUserServiceAccount: validAccessLevels = ValidUserServiceAccountAccessLevels validScopes = ValidUserServiceAccountTokenScopes noEmptyScopes = false skipFields = []string{"config_name", "access_level"} - case token.TokenTypeGroupServiceAccount: + case token.TypeGroupServiceAccount: validAccessLevels = ValidGroupServiceAccountAccessLevels validScopes = ValidGroupServiceAccountTokenScopes noEmptyScopes = false skipFields = []string{"config_name", "access_level"} - case token.TokenTypePipelineProjectTrigger: + case token.TypePipelineProjectTrigger: validAccessLevels = ValidPipelineProjectTriggerAccessLevels validScopes = []string{} noEmptyScopes = false skipFields = []string{"config_name", "access_level", "scopes"} - case token.TokenTypeProjectDeploy: + case token.TypeProjectDeploy: validAccessLevels = ValidProjectDeployAccessLevels validScopes = ValidProjectDeployTokenScopes noEmptyScopes = true skipFields = []string{"config_name", "access_level"} - case token.TokenTypeGroupDeploy: + case token.TypeGroupDeploy: validAccessLevels = ValidGroupDeployAccessLevels validScopes = ValidGroupDeployTokenScopes noEmptyScopes = true @@ -302,13 +302,13 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data } val, ok, _ := data.GetOkErr(name) - if (tokenType == token.TokenTypePersonal && name == "access_level") || + if (tokenType == token.TypePersonal && name == "access_level") || name == "gitlab_revokes_token" { continue } var required = field.Required - if name == "ttl" && !slices.Contains([]token.TokenType{token.TokenTypePipelineProjectTrigger}, tokenType) { + if name == "ttl" && !slices.Contains([]token.Type{token.TypePipelineProjectTrigger}, tokenType) { required = true } @@ -349,7 +349,7 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data err = multierror.Append(err, fmt.Errorf("should be one or more of '%v': %w", validScopes, errs.ErrFieldInvalidValue)) } - if tokenType == token.TokenTypeUserServiceAccount && (config.Type == gitlab.TypeSaaS || config.Type == gitlab.TypeDedicated) { + if tokenType == token.TypeUserServiceAccount && (config.Type == gitlab.TypeSaaS || config.Type == gitlab.TypeDedicated) { err = multierror.Append(err, fmt.Errorf("cannot create %s with %s: %w", tokenType, config.Type, errs.ErrInvalidValue)) } diff --git a/path_role_deploy_tokens_test.go b/path_role_deploy_tokens_test.go index f703e34..1b7828c 100644 --- a/path_role_deploy_tokens_test.go +++ b/path_role_deploy_tokens_test.go @@ -28,7 +28,7 @@ func TestPathRolesDeployTokens(t *testing.T) { } var tests = []struct { - tokenType token.TokenType + tokenType token.Type accessLevel gitlab.AccessLevel scopes []string ttl string @@ -36,12 +36,12 @@ func TestPathRolesDeployTokens(t *testing.T) { name string }{ { - tokenType: token.TokenTypeProjectDeploy, + tokenType: token.TypeProjectDeploy, path: "example/example", scopes: []string{gitlab.TokenScopeReadRepository.String()}, }, { - tokenType: token.TokenTypeGroupDeploy, + tokenType: token.TypeGroupDeploy, path: "test/test1", scopes: []string{gitlab.TokenScopeReadRepository.String()}, }, diff --git a/path_role_pipeline_project_trigger_token_test.go b/path_role_pipeline_project_trigger_token_test.go index 87c5ccc..9479656 100644 --- a/path_role_pipeline_project_trigger_token_test.go +++ b/path_role_pipeline_project_trigger_token_test.go @@ -38,7 +38,7 @@ func TestPathRolesPipelineProjectTrigger(t *testing.T) { "path": "user", "name": "Example user personal token", "access_level": gitlab.AccessLevelNoPermissions.String(), - "token_type": token.TokenTypePipelineProjectTrigger.String(), + "token_type": token.TypePipelineProjectTrigger.String(), "scopes": []string{gitlab.TokenScopeApi.String()}, "ttl": "1h", }, @@ -60,7 +60,7 @@ func TestPathRolesPipelineProjectTrigger(t *testing.T) { "path": "user", "name": "Example user personal token", "access_level": gitlab.AccessLevelUnknown.String(), - "token_type": token.TokenTypePipelineProjectTrigger.String(), + "token_type": token.TypePipelineProjectTrigger.String(), "scopes": []string{}, "ttl": "1h", }, @@ -81,7 +81,7 @@ func TestPathRolesPipelineProjectTrigger(t *testing.T) { "path": "user", "name": "Example user personal token", "access_level": gitlab.AccessLevelUnknown.String(), - "token_type": token.TokenTypePipelineProjectTrigger.String(), + "token_type": token.TypePipelineProjectTrigger.String(), "scopes": []string{}, }, }) diff --git a/path_role_test.go b/path_role_test.go index d34d27d..e51c85b 100644 --- a/path_role_test.go +++ b/path_role_test.go @@ -70,7 +70,7 @@ func TestPathRoles(t *testing.T) { }) t.Run("access level", func(t *testing.T) { - t.Run(token.TokenTypePersonal.String(), func(t *testing.T) { + t.Run(token.TypePersonal.String(), func(t *testing.T) { t.Run("no access level defined", func(t *testing.T) { ctx := getCtxGitlabClient(t, "unit") var b, l, err = getBackendWithConfig(ctx, defaultConfig) @@ -80,8 +80,8 @@ func TestPathRoles(t *testing.T) { Path: fmt.Sprintf("%s/test", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "user", - "name": token.TokenTypePersonal.String(), - "token_type": token.TokenTypePersonal.String(), + "name": token.TypePersonal.String(), + "token_type": token.TypePersonal.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": gitlab.ValidPersonalTokenScopes, "gitlab_revokes_token": false, @@ -101,9 +101,9 @@ func TestPathRoles(t *testing.T) { Path: fmt.Sprintf("%s/test", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "user", - "name": token.TokenTypePersonal.String(), + "name": token.TypePersonal.String(), "access_level": gitlab.AccessLevelOwnerPermissions.String(), - "token_type": token.TokenTypePersonal.String(), + "token_type": token.TypePersonal.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": gitlab.ValidPersonalTokenScopes, "gitlab_revokes_token": false, @@ -115,7 +115,7 @@ func TestPathRoles(t *testing.T) { }) }) - t.Run(token.TokenTypeProject.String(), func(t *testing.T) { + t.Run(token.TypeProject.String(), func(t *testing.T) { t.Run("no access level defined", func(t *testing.T) { ctx := getCtxGitlabClient(t, "unit") var b, l, err = getBackendWithConfig(ctx, defaultConfig) @@ -125,8 +125,8 @@ func TestPathRoles(t *testing.T) { Path: fmt.Sprintf("%s/test", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "user", - "name": token.TokenTypeProject.String(), - "token_type": token.TokenTypeProject.String(), + "name": token.TypeProject.String(), + "token_type": token.TypeProject.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": gitlab.ValidProjectTokenScopes, "gitlab_revokes_token": false, @@ -145,9 +145,9 @@ func TestPathRoles(t *testing.T) { Path: fmt.Sprintf("%s/test", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "user", - "name": token.TokenTypeProject.String(), + "name": token.TypeProject.String(), "access_level": gitlab.AccessLevelOwnerPermissions.String(), - "token_type": token.TokenTypeProject.String(), + "token_type": token.TypeProject.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": gitlab.ValidProjectTokenScopes, "gitlab_revokes_token": false, @@ -160,7 +160,7 @@ func TestPathRoles(t *testing.T) { }) }) - t.Run(token.TokenTypeGroup.String(), func(t *testing.T) { + t.Run(token.TypeGroup.String(), func(t *testing.T) { t.Run("no access level defined", func(t *testing.T) { ctx := getCtxGitlabClient(t, "unit") var b, l, err = getBackendWithConfig(ctx, defaultConfig) @@ -170,8 +170,8 @@ func TestPathRoles(t *testing.T) { Path: fmt.Sprintf("%s/test", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "user", - "name": token.TokenTypeGroup.String(), - "token_type": token.TokenTypeGroup.String(), + "name": token.TypeGroup.String(), + "token_type": token.TypeGroup.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": gitlab.ValidGroupTokenScopes, "gitlab_revokes_token": false, @@ -190,9 +190,9 @@ func TestPathRoles(t *testing.T) { Path: fmt.Sprintf("%s/test", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "user", - "name": token.TokenTypeGroup.String(), + "name": token.TypeGroup.String(), "access_level": gitlab.AccessLevelOwnerPermissions.String(), - "token_type": token.TokenTypeGroup.String(), + "token_type": token.TypeGroup.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": gitlab.ValidGroupTokenScopes, "gitlab_revokes_token": false, @@ -235,7 +235,7 @@ func TestPathRoles(t *testing.T) { Data: map[string]any{ "path": "user", "name": "{{ . } invalid template", - "token_type": token.TokenTypePersonal.String(), + "token_type": token.TypePersonal.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": gitlab.ValidPersonalTokenScopes, "gitlab_revokes_token": false, @@ -260,7 +260,7 @@ func TestPathRoles(t *testing.T) { "name": "Example user personal token", "access_level": gitlab.AccessLevelOwnerPermissions.String(), "ttl": "48h", - "token_type": token.TokenTypeProject.String(), + "token_type": token.TypeProject.String(), "scopes": gitlab.ValidProjectTokenScopes, }, }) @@ -280,7 +280,7 @@ func TestPathRoles(t *testing.T) { "path": "user", "name": "Example project personal token", "access_level": gitlab.AccessLevelOwnerPermissions.String(), - "token_type": token.TokenTypeProject.String(), + "token_type": token.TypeProject.String(), "ttl": "48h", "scopes": gitlab.ValidPersonalTokenScopes, "gitlab_revokes_token": false, @@ -305,7 +305,7 @@ func TestPathRoles(t *testing.T) { "path": "user", "name": "Example user personal token", "ttl": "48h", - "token_type": token.TokenTypePersonal.String(), + "token_type": token.TypePersonal.String(), "scopes": gitlab.ValidPersonalTokenScopes, }, }) @@ -324,7 +324,7 @@ func TestPathRoles(t *testing.T) { Data: map[string]any{ "path": "user", "name": "Example user personal token", - "token_type": token.TokenTypePersonal.String(), + "token_type": token.TypePersonal.String(), "scopes": []string{ "invalid_scope", }, @@ -350,7 +350,7 @@ func TestPathRoles(t *testing.T) { "name": "Example user personal token", "ttl": "48h", "access_level": gitlab.AccessLevelOwnerPermissions.String(), - "token_type": token.TokenTypeGroup.String(), + "token_type": token.TypeGroup.String(), "scopes": gitlab.ValidProjectTokenScopes, }, }) @@ -370,7 +370,7 @@ func TestPathRoles(t *testing.T) { "path": "user", "name": "Example user personal token", "access_level": gitlab.AccessLevelOwnerPermissions.String(), - "token_type": token.TokenTypeGroup.String(), + "token_type": token.TypeGroup.String(), "scopes": gitlab.ValidPersonalTokenScopes, }, }) @@ -420,7 +420,7 @@ func TestPathRoles(t *testing.T) { var roleData = map[string]any{ "path": "user", "name": "Example user personal token", - "token_type": token.TokenTypePersonal.String(), + "token_type": token.TypePersonal.String(), "ttl": int64((5 * 24 * time.Hour).Seconds()), "gitlab_revokes_token": false, "scopes": []string{ diff --git a/path_role_ttl_test.go b/path_role_ttl_test.go index 2f21956..27332d7 100644 --- a/path_role_ttl_test.go +++ b/path_role_ttl_test.go @@ -30,7 +30,7 @@ func TestPathRolesTTL(t *testing.T) { var generalRole = map[string]any{ "path": "user", "name": "Example user personal token", - "token_type": token.TokenTypePersonal.String(), + "token_type": token.TypePersonal.String(), "scopes": []string{ gitlab.TokenScopeApi.String(), gitlab.TokenScopeReadRegistry.String(), @@ -91,7 +91,7 @@ func TestPathRolesTTL(t *testing.T) { var generalRole = map[string]any{ "path": "user", "name": "Example user personal token", - "token_type": token.TokenTypePersonal.String(), + "token_type": token.TypePersonal.String(), "scopes": []string{ gitlab.TokenScopeApi.String(), gitlab.TokenScopeReadRegistry.String(), @@ -153,7 +153,7 @@ func TestPathRolesTTL(t *testing.T) { var generalRole = map[string]any{ "path": "user", "name": "Example user personal token", - "token_type": token.TokenTypePersonal.String(), + "token_type": token.TypePersonal.String(), "scopes": []string{ gitlab.TokenScopeApi.String(), gitlab.TokenScopeReadRegistry.String(), diff --git a/path_token_role.go b/path_token_role.go index b1d92ed..a571511 100644 --- a/path_token_role.go +++ b/path_token_role.go @@ -81,26 +81,26 @@ func (b *Backend) pathTokenRoleCreate(ctx context.Context, req *logical.Request, } switch role.TokenType { - case token2.TokenTypeGroup: + case token2.TypeGroup: b.Logger().Debug("Creating group access token for role", "path", role.Path, "name", name, "expiresAt", expiresAt, "scopes", role.Scopes, "accessLevel", role.AccessLevel) token, err = client.CreateGroupAccessToken(ctx, role.Path, name, expiresAt, role.Scopes, role.AccessLevel) - case token2.TokenTypeProject: + case token2.TypeProject: b.Logger().Debug("Creating project access token for role", "path", role.Path, "name", name, "expiresAt", expiresAt, "scopes", role.Scopes, "accessLevel", role.AccessLevel) token, err = client.CreateProjectAccessToken(ctx, role.Path, name, expiresAt, role.Scopes, role.AccessLevel) - case token2.TokenTypePersonal: + case token2.TypePersonal: var userId int userId, err = client.GetUserIdByUsername(ctx, role.Path) if err == nil { b.Logger().Debug("Creating personal access token for role", "path", role.Path, "userId", userId, "name", name, "expiresAt", expiresAt, "scopes", role.Scopes) token, err = client.CreatePersonalAccessToken(ctx, role.Path, userId, name, expiresAt, role.Scopes) } - case token2.TokenTypeUserServiceAccount: + case token2.TypeUserServiceAccount: var userId int if userId, err = client.GetUserIdByUsername(ctx, role.Path); err == nil { b.Logger().Debug("Creating user service account access token for role", "path", role.Path, "userId", userId, "name", name, "expiresAt", expiresAt, "scopes", role.Scopes) token, err = client.CreateUserServiceAccountAccessToken(ctx, role.Path, userId, name, expiresAt, role.Scopes) } - case token2.TokenTypeGroupServiceAccount: + case token2.TypeGroupServiceAccount: var serviceAccount, groupId string { parts := strings.Split(role.Path, "/") @@ -112,17 +112,17 @@ func (b *Backend) pathTokenRoleCreate(ctx context.Context, req *logical.Request, b.Logger().Debug("Creating group service account access token for role", "path", role.Path, "groupId", groupId, "userId", userId, "name", name, "expiresAt", expiresAt, "scopes", role.Scopes) token, err = client.CreateGroupServiceAccountAccessToken(ctx, role.Path, groupId, userId, name, expiresAt, role.Scopes) } - case token2.TokenTypeProjectDeploy: + case token2.TypeProjectDeploy: var projectId int if projectId, err = client.GetProjectIdByPath(ctx, role.Path); err == nil { token, err = client.CreateProjectDeployToken(ctx, role.Path, projectId, name, &expiresAt, role.Scopes) } - case token2.TokenTypeGroupDeploy: + case token2.TypeGroupDeploy: var groupId int if groupId, err = client.GetGroupIdByPath(ctx, role.Path); err == nil { token, err = client.CreateGroupDeployToken(ctx, role.Path, groupId, name, &expiresAt, role.Scopes) } - case token2.TokenTypePipelineProjectTrigger: + case token2.TypePipelineProjectTrigger: var projectId int if projectId, err = client.GetProjectIdByPath(ctx, role.Path); err == nil { token, err = client.CreatePipelineProjectTriggerAccessToken(ctx, role.Path, name, projectId, name, &expiresAt) diff --git a/path_token_role_multiple_config_test.go b/path_token_role_multiple_config_test.go index e277b4a..74cf64f 100644 --- a/path_token_role_multiple_config_test.go +++ b/path_token_role_multiple_config_test.go @@ -46,7 +46,7 @@ func TestPathTokenRolesMultipleConfigs(t *testing.T) { type roleData struct { roleName, path, tokenName string - tokenType token.TokenType + tokenType token.Type accessLevel gitlab.AccessLevel scopes []string } @@ -55,14 +55,14 @@ func TestPathTokenRolesMultipleConfigs(t *testing.T) { { roleName: "root-root", path: "root", - tokenType: token.TokenTypePersonal, + tokenType: token.TypePersonal, scopes: []string{gitlab.TokenScopeApi.String(), gitlab.TokenScopeSelfRotate.String()}, tokenName: "admin_user_root", }, { roleName: "root-normal-user", path: "normal-user", - tokenType: token.TokenTypePersonal, + tokenType: token.TypePersonal, scopes: []string{gitlab.TokenScopeApi.String(), gitlab.TokenScopeSelfRotate.String()}, tokenName: "admin_user_root", }, @@ -71,7 +71,7 @@ func TestPathTokenRolesMultipleConfigs(t *testing.T) { { roleName: "admin-example-example", path: "example/example", - tokenType: token.TokenTypeProject, + tokenType: token.TypeProject, accessLevel: gitlab.AccessLevelGuestPermissions, scopes: []string{gitlab.TokenScopeApi.String(), gitlab.TokenScopeSelfRotate.String()}, tokenName: "admin_user_initial_token", @@ -81,7 +81,7 @@ func TestPathTokenRolesMultipleConfigs(t *testing.T) { { roleName: "normal-example", path: "example", - tokenType: token.TokenTypeGroup, + tokenType: token.TypeGroup, accessLevel: gitlab.AccessLevelGuestPermissions, scopes: []string{gitlab.TokenScopeApi.String(), gitlab.TokenScopeSelfRotate.String()}, tokenName: "normal_user_initial_token", @@ -98,13 +98,13 @@ func TestPathTokenRolesMultipleConfigs(t *testing.T) { } switch rd.tokenType { - case token.TokenTypePersonal: + case token.TypePersonal: data["access_level"] = rd.accessLevel.String() data["scopes"] = rd.scopes - case token.TokenTypeGroup: + case token.TypeGroup: data["access_level"] = rd.accessLevel.String() data["scopes"] = rd.scopes - case token.TokenTypeProject: + case token.TypeProject: data["access_level"] = rd.accessLevel.String() data["scopes"] = rd.scopes } diff --git a/path_token_role_test.go b/path_token_role_test.go index ab3984f..9bd28df 100644 --- a/path_token_role_test.go +++ b/path_token_role_test.go @@ -37,7 +37,7 @@ func TestPathTokenRoles(t *testing.T) { require.ErrorIs(t, err, gitlab.ErrRoleNotFound) }) - var generalTokenCreation = func(t *testing.T, tokenType token.TokenType, level gitlab.AccessLevel, gitlabRevokesToken bool) { + var generalTokenCreation = func(t *testing.T, tokenType token.Type, level gitlab.AccessLevel, gitlabRevokesToken bool) { t.Logf("token creation, token type: %s, level: %s, gitlab revokes token: %t", tokenType, level, gitlabRevokesToken) ctx := getCtxGitlabClient(t, "unit") client := newInMemoryClient(true) @@ -58,11 +58,11 @@ func TestPathTokenRoles(t *testing.T) { var path string switch tokenType { - case token.TokenTypeProject: + case token.TypeProject: path = "example/example" - case token.TokenTypePersonal: + case token.TypePersonal: path = "admin-user" - case token.TokenTypeGroup: + case token.TypeGroup: path = "example" } @@ -125,11 +125,11 @@ func TestPathTokenRoles(t *testing.T) { if !gitlabRevokesToken { // calling revoke again would return a token not found in internal error switch tokenType { - case token.TokenTypeProject: + case token.TypeProject: client.projectAccessTokenRevokeError = true - case token.TokenTypePersonal: + case token.TypePersonal: client.personalAccessTokenRevokeError = true - case token.TokenTypeGroup: + case token.TypeGroup: client.groupAccessTokenRevokeError = true } resp, err = b.HandleRequest(ctx, &logical.Request{ @@ -152,17 +152,17 @@ func TestPathTokenRoles(t *testing.T) { } t.Run("personal access token", func(t *testing.T) { - generalTokenCreation(t, token.TokenTypePersonal, gitlab.AccessLevelUnknown, false) - generalTokenCreation(t, token.TokenTypePersonal, gitlab.AccessLevelUnknown, true) + generalTokenCreation(t, token.TypePersonal, gitlab.AccessLevelUnknown, false) + generalTokenCreation(t, token.TypePersonal, gitlab.AccessLevelUnknown, true) }) t.Run("project access token", func(t *testing.T) { - generalTokenCreation(t, token.TokenTypeProject, gitlab.AccessLevelGuestPermissions, false) - generalTokenCreation(t, token.TokenTypeProject, gitlab.AccessLevelGuestPermissions, true) + generalTokenCreation(t, token.TypeProject, gitlab.AccessLevelGuestPermissions, false) + generalTokenCreation(t, token.TypeProject, gitlab.AccessLevelGuestPermissions, true) }) t.Run("group access token", func(t *testing.T) { - generalTokenCreation(t, token.TokenTypeGroup, gitlab.AccessLevelGuestPermissions, false) - generalTokenCreation(t, token.TokenTypeGroup, gitlab.AccessLevelGuestPermissions, true) + generalTokenCreation(t, token.TypeGroup, gitlab.AccessLevelGuestPermissions, false) + generalTokenCreation(t, token.TypeGroup, gitlab.AccessLevelGuestPermissions, true) }) } diff --git a/secret_access_tokens.go b/secret_access_tokens.go index 6dfb732..2cc2b50 100644 --- a/secret_access_tokens.go +++ b/secret_access_tokens.go @@ -81,9 +81,9 @@ func (b *Backend) secretAccessTokenRevoke(ctx context.Context, req *logical.Requ var gitlabRevokesToken = req.Secret.InternalData["gitlab_revokes_token"].(bool) var vaultRevokesToken = !gitlabRevokesToken var parentId = req.Secret.InternalData["parent_id"].(string) - var tokenType token.TokenType + var tokenType token.Type var tokenTypeValue = req.Secret.InternalData["token_type"].(string) - tokenType, _ = token.TokenTypeParse(tokenTypeValue) + tokenType, _ = token.TypeParse(tokenTypeValue) if vaultRevokesToken { var client Client @@ -93,29 +93,29 @@ func (b *Backend) secretAccessTokenRevoke(ctx context.Context, req *logical.Requ } switch tokenType { - case token.TokenTypePersonal: + case token.TypePersonal: err = client.RevokePersonalAccessToken(ctx, tokenId) - case token.TokenTypeProject: + case token.TypeProject: err = client.RevokeProjectAccessToken(ctx, tokenId, parentId) - case token.TokenTypeGroup: + case token.TypeGroup: err = client.RevokeGroupAccessToken(ctx, tokenId, parentId) - case token.TokenTypeUserServiceAccount: + case token.TypeUserServiceAccount: var token = req.Secret.InternalData["token"].(string) err = client.RevokeUserServiceAccountAccessToken(ctx, token) - case token.TokenTypeGroupServiceAccount: + case token.TypeGroupServiceAccount: var token = req.Secret.InternalData["token"].(string) err = client.RevokeGroupServiceAccountAccessToken(ctx, token) - case token.TokenTypePipelineProjectTrigger: + case token.TypePipelineProjectTrigger: var projectId int if projectId, err = strconv.Atoi(parentId); err == nil { err = client.RevokePipelineProjectTriggerAccessToken(ctx, projectId, tokenId) } - case token.TokenTypeGroupDeploy: + case token.TypeGroupDeploy: var groupId int if groupId, err = strconv.Atoi(parentId); err == nil { err = client.RevokeGroupDeployToken(ctx, groupId, tokenId) } - case token.TokenTypeProjectDeploy: + case token.TypeProjectDeploy: var projectId int if projectId, err = strconv.Atoi(parentId); err == nil { err = client.RevokeProjectDeployToken(ctx, projectId, tokenId) diff --git a/token.go b/token.go index 6187235..5a71e7b 100644 --- a/token.go +++ b/token.go @@ -14,7 +14,7 @@ type IToken interface { Internal() map[string]any Data() map[string]any Event(map[string]string) map[string]string - Type() token.TokenType + Type() token.Type SetConfigName(string) SetRoleName(string) SetGitlabRevokesToken(bool) @@ -25,17 +25,17 @@ type IToken interface { } type Token struct { - RoleName string `json:"role_name"` - ConfigName string `json:"config_name"` - GitlabRevokesToken bool `json:"gitlab_revokes_token"` - CreatedAt *time.Time `json:"created_at"` - ExpiresAt *time.Time `json:"expires_at"` - TokenType token.TokenType `json:"type"` - Token string `json:"token"` - TokenID int `json:"token_id"` - ParentID string `json:"parent_id"` - Name string `json:"name"` - Path string `json:"path"` + RoleName string `json:"role_name"` + ConfigName string `json:"config_name"` + GitlabRevokesToken bool `json:"gitlab_revokes_token"` + CreatedAt *time.Time `json:"created_at"` + ExpiresAt *time.Time `json:"expires_at"` + TokenType token.Type `json:"type"` + Token string `json:"token"` + TokenID int `json:"token_id"` + ParentID string `json:"parent_id"` + Name string `json:"name"` + Path string `json:"path"` } func (t *Token) TTL() time.Duration { @@ -58,7 +58,7 @@ func (t *Token) SetExpiresAt(expiresAt *time.Time) { t.ExpiresAt = expiresAt } func (t *Token) SetConfigName(name string) { t.ConfigName = name } func (t *Token) SetRoleName(name string) { t.RoleName = name } func (t *Token) SetGitlabRevokesToken(b bool) { t.GitlabRevokesToken = b } -func (t *Token) Type() token.TokenType { return t.TokenType } +func (t *Token) Type() token.Type { return t.TokenType } func (t *Token) Internal() map[string]any { return map[string]any{ diff --git a/with_admin_user_pat_gitlab_revokes_token_test.go b/with_admin_user_pat_gitlab_revokes_token_test.go index 7e441e4..e38dc6c 100644 --- a/with_admin_user_pat_gitlab_revokes_token_test.go +++ b/with_admin_user_pat_gitlab_revokes_token_test.go @@ -54,8 +54,8 @@ func TestWithAdminUser_PAT_AdminUser_GitlabRevokesToken(t *testing.T) { Path: fmt.Sprintf("%s/normal-user", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "normal-user", - "name": token2.TokenTypePersonal.String(), - "token_type": token2.TokenTypePersonal.String(), + "name": token2.TypePersonal.String(), + "token_type": token2.TypePersonal.String(), "ttl": time.Hour * 120, "gitlab_revokes_token": strconv.FormatBool(true), "scopes": strings.Join( diff --git a/with_admin_user_pat_vault_revokes_token_test.go b/with_admin_user_pat_vault_revokes_token_test.go index a743012..fab365a 100644 --- a/with_admin_user_pat_vault_revokes_token_test.go +++ b/with_admin_user_pat_vault_revokes_token_test.go @@ -55,8 +55,8 @@ func TestWithAdminUser_PAT_AdminUser_VaultRevokesToken(t *testing.T) { Path: fmt.Sprintf("%s/admin-user", gitlab.PathRoleStorage), Data: map[string]any{ "path": "admin-user", - "name": token2.TokenTypePersonal.String(), - "token_type": token2.TokenTypePersonal.String(), + "name": token2.TypePersonal.String(), + "token_type": token2.TypePersonal.String(), "scopes": strings.Join( []string{ gitlab.TokenScopeReadApi.String(), diff --git a/with_group_deploy_token_test.go b/with_group_deploy_token_test.go index 0b07e3a..11f8332 100644 --- a/with_group_deploy_token_test.go +++ b/with_group_deploy_token_test.go @@ -52,8 +52,8 @@ func TestWithGroupDeployToken(t *testing.T) { Path: fmt.Sprintf("%s/role", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "example", - "name": token2.TokenTypeGroupDeploy.String(), - "token_type": token2.TokenTypeGroupDeploy.String(), + "name": token2.TypeGroupDeploy.String(), + "token_type": token2.TypeGroupDeploy.String(), "gitlab_revokes_token": strconv.FormatBool(false), "ttl": 120 * time.Hour, "scopes": []string{gitlab.TokenScopeReadRepository.String()}, diff --git a/with_normal_user_gat_test.go b/with_normal_user_gat_test.go index 7fedfe8..e14b70b 100644 --- a/with_normal_user_gat_test.go +++ b/with_normal_user_gat_test.go @@ -54,7 +54,7 @@ func TestWithNormalUser_GAT(t *testing.T) { Data: map[string]any{ "path": "example", "name": `gat-token`, - "token_type": token2.TokenTypeGroup.String(), + "token_type": token2.TypeGroup.String(), "ttl": time.Hour * 120, "gitlab_revokes_token": strconv.FormatBool(false), "access_level": gitlab.AccessLevelMaintainerPermissions.String(), diff --git a/with_normal_user_personal_at_fails_test.go b/with_normal_user_personal_at_fails_test.go index a4834f2..5551e9d 100644 --- a/with_normal_user_personal_at_fails_test.go +++ b/with_normal_user_personal_at_fails_test.go @@ -48,8 +48,8 @@ func TestWithNormalUser_PersonalAT_Fails(t *testing.T) { Path: fmt.Sprintf("%s/normal-user", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "normal-user", - "name": token.TokenTypePersonal.String(), - "token_type": token.TokenTypePersonal.String(), + "name": token.TypePersonal.String(), + "token_type": token.TypePersonal.String(), "ttl": time.Hour * 120, "gitlab_revokes_token": strconv.FormatBool(true), "scopes": strings.Join( diff --git a/with_normal_user_project_at_test.go b/with_normal_user_project_at_test.go index 4c9510e..8a9bc22 100644 --- a/with_normal_user_project_at_test.go +++ b/with_normal_user_project_at_test.go @@ -54,8 +54,8 @@ func TestWithNormalUser_ProjectAT(t *testing.T) { Path: fmt.Sprintf("%s/pat", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "example/example", - "name": tok.TokenTypeProject.String(), - "token_type": tok.TokenTypeProject.String(), + "name": tok.TypeProject.String(), + "token_type": tok.TypeProject.String(), "ttl": time.Hour * 120, "gitlab_revokes_token": strconv.FormatBool(false), "access_level": gitlab.AccessLevelMaintainerPermissions.String(), diff --git a/with_pipeline_project_trigger_token_test.go b/with_pipeline_project_trigger_token_test.go index 212c3d1..f65cd59 100644 --- a/with_pipeline_project_trigger_token_test.go +++ b/with_pipeline_project_trigger_token_test.go @@ -51,8 +51,8 @@ func TestWithPipelineProjectTriggerAccessToken(t *testing.T) { Path: fmt.Sprintf("%s/pptat", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "example/example", - "name": token2.TokenTypePipelineProjectTrigger.String(), - "token_type": token2.TokenTypePipelineProjectTrigger.String(), + "name": token2.TypePipelineProjectTrigger.String(), + "token_type": token2.TypePipelineProjectTrigger.String(), "gitlab_revokes_token": strconv.FormatBool(false), }, }) diff --git a/with_project_deploy_token_test.go b/with_project_deploy_token_test.go index e3e0c88..d3db2c4 100644 --- a/with_project_deploy_token_test.go +++ b/with_project_deploy_token_test.go @@ -52,8 +52,8 @@ func TestWithProjectDeployToken(t *testing.T) { Path: fmt.Sprintf("%s/role", gitlab.PathRoleStorage), Storage: l, Data: map[string]any{ "path": "example/example", - "name": token2.TokenTypeProjectDeploy.String(), - "token_type": token2.TokenTypeProjectDeploy.String(), + "name": token2.TypeProjectDeploy.String(), + "token_type": token2.TypeProjectDeploy.String(), "gitlab_revokes_token": strconv.FormatBool(false), "ttl": 120 * time.Hour, "scopes": []string{gitlab.TokenScopeReadRepository.String()}, diff --git a/with_service_account_fail_test.go b/with_service_account_fail_test.go index df31974..039c001 100644 --- a/with_service_account_fail_test.go +++ b/with_service_account_fail_test.go @@ -58,7 +58,7 @@ func TestWithServiceAccountUserFail(t *testing.T) { Data: map[string]any{ "path": usr.Username, "name": fmt.Sprintf(`user-service-account-%s`, usr.Username), - "token_type": token.TokenTypeUserServiceAccount.String(), + "token_type": token.TypeUserServiceAccount.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": gitlab.ValidUserServiceAccountTokenScopes, "gitlab_revokes_token": false, diff --git a/with_service_account_group_test.go b/with_service_account_group_test.go index 75421ca..be9e78a 100644 --- a/with_service_account_group_test.go +++ b/with_service_account_group_test.go @@ -63,7 +63,7 @@ func TestWithServiceAccountGroup(t *testing.T) { Data: map[string]any{ "path": fmt.Sprintf("%s/%s", gid, sa.UserName), "name": `vault-generated-{{ .token_type }}-token`, - "token_type": token2.TokenTypeGroupServiceAccount.String(), + "token_type": token2.TypeGroupServiceAccount.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": gitlab.ValidGroupServiceAccountTokenScopes, "gitlab_revokes_token": false, diff --git a/with_service_account_user_test.go b/with_service_account_user_test.go index 6bd552e..769659f 100644 --- a/with_service_account_user_test.go +++ b/with_service_account_user_test.go @@ -61,7 +61,7 @@ func TestWithServiceAccountUser(t *testing.T) { Data: map[string]any{ "path": usr.Username, "name": `vault-generated-{{ .token_type }}-token`, - "token_type": token2.TokenTypeUserServiceAccount.String(), + "token_type": token2.TypeUserServiceAccount.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": gitlab.ValidUserServiceAccountTokenScopes, "gitlab_revokes_token": false, From 7a0efe038ea5836f473591077683fff48e61b0cb Mon Sep 17 00:00:00 2001 From: Ilija Matoski Date: Mon, 16 Jun 2025 17:59:17 +0200 Subject: [PATCH 07/17] moved events to its own pkg --- events.go => internal/event/event.go | 7 ++-- internal/event/event_test.go | 63 ++++++++++++++++++++++++++++ path_config.go | 7 ++-- path_config_rotate.go | 3 +- path_flags.go | 4 +- path_role.go | 5 ++- path_token_role.go | 5 ++- secret_access_tokens.go | 3 +- 8 files changed, 84 insertions(+), 13 deletions(-) rename events.go => internal/event/event.go (65%) create mode 100644 internal/event/event_test.go diff --git a/events.go b/internal/event/event.go similarity index 65% rename from events.go rename to internal/event/event.go index a36b5f1..1801f15 100644 --- a/events.go +++ b/internal/event/event.go @@ -1,4 +1,4 @@ -package gitlab +package event import ( "context" @@ -10,7 +10,7 @@ import ( "google.golang.org/protobuf/types/known/structpb" ) -func Event(ctx context.Context, b *framework.Backend, eventType string, metadata map[string]string) { +func Event(ctx context.Context, b *framework.Backend, prefix, eventType string, metadata map[string]string) error { var err error var ev *logical.EventData if ev, err = logical.NewEvent(); err == nil { @@ -18,6 +18,7 @@ func Event(ctx context.Context, b *framework.Backend, eventType string, metadata metadataBytes, _ = json.Marshal(metadata) ev.Metadata = &structpb.Struct{} _ = ev.Metadata.UnmarshalJSON(metadataBytes) - _ = b.SendEvent(ctx, logical.EventType(fmt.Sprintf("%s/%s", operationPrefixGitlabAccessTokens, eventType)), ev) + err = b.SendEvent(ctx, logical.EventType(fmt.Sprintf("%s/%s", prefix, eventType)), ev) } + return err } diff --git a/internal/event/event_test.go b/internal/event/event_test.go new file mode 100644 index 0000000..6beb56d --- /dev/null +++ b/internal/event/event_test.go @@ -0,0 +1,63 @@ +package event_test + +import ( + "context" + "sync" + "testing" + + "github.com/hashicorp/vault/sdk/framework" + "github.com/hashicorp/vault/sdk/logical" + "github.com/stretchr/testify/require" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/event" +) + +type mockEventsSender struct { + events []*logical.EventReceived + mu sync.Mutex +} + +var _ logical.EventSender = (*mockEventsSender)(nil) + +func (m *mockEventsSender) SendEvent(ctx context.Context, eventType logical.EventType, event *logical.EventData) error { + if m == nil { + return nil + } + m.mu.Lock() + defer m.mu.Unlock() + m.events = append(m.events, &logical.EventReceived{ + EventType: string(eventType), + Event: event, + }) + return nil +} + +func TestEvent(t *testing.T) { + t.Run("no sender specified", func(t *testing.T) { + b := &framework.Backend{} + require.NoError(t, b.Setup(t.Context(), &logical.BackendConfig{})) + require.ErrorIs(t, + event.Event( + t.Context(), + &framework.Backend{}, + "test", "test", + map[string]string{"test": "test"}, + ), + framework.ErrNoEvents, + ) + }) + + t.Run("with event sender", func(t *testing.T) { + b := &framework.Backend{} + evt := &mockEventsSender{} + require.NoError(t, b.Setup(t.Context(), &logical.BackendConfig{EventsSender: evt})) + require.NoError(t, + event.Event( + t.Context(), b, + "test", "test", + map[string]string{"test": "test"}, + ), + ) + require.Len(t, evt.events, 1) + }) +} diff --git a/path_config.go b/path_config.go index 39e1ad4..281335b 100644 --- a/path_config.go +++ b/path_config.go @@ -13,6 +13,7 @@ import ( g "gitlab.com/gitlab-org/api/client-go" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/event" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" ) @@ -91,7 +92,7 @@ func (b *Backend) pathConfigDelete(ctx context.Context, req *logical.Request, da } if err = req.Storage.Delete(ctx, fmt.Sprintf("%s/%s", PathConfigStorage, name)); err == nil { - Event(ctx, b.Backend, "config-delete", map[string]string{ + event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "config-delete", map[string]string{ "path": fmt.Sprintf("%s/%s", PathConfigStorage, name), }) b.SetClient(nil, name) @@ -146,7 +147,7 @@ func (b *Backend) pathConfigPatch(ctx context.Context, req *logical.Request, dat defer b.lockClientMutex.Unlock() if err = saveConfig(ctx, *config, req.Storage); err == nil { lrd := config.LogicalResponseData(b.flags.ShowConfigToken) - Event(ctx, b.Backend, "config-patch", changes) + event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "config-patch", changes) b.SetClient(nil, name) b.Logger().Debug("Patched config", "lrd", lrd, "warnings", warnings) lResp = &logical.Response{Data: lrd, Warnings: warnings} @@ -205,7 +206,7 @@ func (b *Backend) pathConfigWrite(ctx context.Context, req *logical.Request, dat var lResp *logical.Response if err = saveConfig(ctx, *config, req.Storage); err == nil { - Event(ctx, b.Backend, "config-write", map[string]string{ + event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "config-write", map[string]string{ "path": fmt.Sprintf("%s/%s", PathConfigStorage, name), "auto_rotate_token": strconv.FormatBool(config.AutoRotateToken), "auto_rotate_before": config.AutoRotateBefore.String(), diff --git a/path_config_rotate.go b/path_config_rotate.go index 2a941b8..195f8ff 100644 --- a/path_config_rotate.go +++ b/path_config_rotate.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/vault/sdk/logical" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/event" ) const pathConfigRotateHelpSynopsis = `Rotate the gitlab token for this configuration.` @@ -105,7 +106,7 @@ func (b *Backend) pathConfigTokenRotate(ctx context.Context, request *logical.Re lResp = &logical.Response{Data: config.LogicalResponseData(b.flags.ShowConfigToken)} lResp.Data["token"] = config.Token - Event(ctx, b.Backend, "config-token-rotate", map[string]string{ + event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "config-token-rotate", map[string]string{ "path": fmt.Sprintf("%s/%s", PathConfigStorage, name), "expires_at": entryToken.ExpiresAt.Format(time.RFC3339), "created_at": entryToken.CreatedAt.Format(time.RFC3339), diff --git a/path_flags.go b/path_flags.go index ac816a3..a0102a0 100644 --- a/path_flags.go +++ b/path_flags.go @@ -9,6 +9,8 @@ import ( "github.com/hashicorp/vault/sdk/framework" "github.com/hashicorp/vault/sdk/logical" "github.com/mitchellh/mapstructure" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/event" ) const ( @@ -43,7 +45,7 @@ func (b *Backend) pathFlagsUpdate(ctx context.Context, req *logical.Request, dat eventData["show_config_token"] = strconv.FormatBool(b.flags.ShowConfigToken) } - Event(ctx, b.Backend, "flags-write", eventData) + event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "flags-write", eventData) var flagData map[string]any err = mapstructure.Decode(b.flags, &flagData) diff --git a/path_role.go b/path_role.go index 7719793..0c2049d 100644 --- a/path_role.go +++ b/path_role.go @@ -16,6 +16,7 @@ import ( "github.com/hashicorp/vault/sdk/logical" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/event" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" @@ -166,7 +167,7 @@ func (b *Backend) pathRolesDelete(ctx context.Context, req *logical.Request, dat return nil, fmt.Errorf("error deleting role: %w", err) } - Event(ctx, b.Backend, "role-delete", map[string]string{ + event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "role-delete", map[string]string{ "path": "roles", "role_name": roleName, }) @@ -370,7 +371,7 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data return nil, err } - Event(ctx, b.Backend, "role-write", map[string]string{ + event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "role-write", map[string]string{ "path": "roles", "role_name": roleName, "config_name": role.ConfigName, diff --git a/path_token_role.go b/path_token_role.go index a571511..dc6c886 100644 --- a/path_token_role.go +++ b/path_token_role.go @@ -13,6 +13,7 @@ import ( "github.com/hashicorp/vault/sdk/logical" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/event" token2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) @@ -155,8 +156,8 @@ func (b *Backend) pathTokenRoleCreate(ctx context.Context, req *logical.Request, resp.Secret.TTL = token.TTL() } - Event( - ctx, b.Backend, "token-write", + event.Event( + ctx, b.Backend, operationPrefixGitlabAccessTokens, "token-write", token.Event(map[string]string{"path": fmt.Sprintf("%s/%s", PathRoleStorage, roleName)}), ) return resp, nil diff --git a/secret_access_tokens.go b/secret_access_tokens.go index 2cc2b50..d727bad 100644 --- a/secret_access_tokens.go +++ b/secret_access_tokens.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/vault/sdk/logical" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/event" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) @@ -127,7 +128,7 @@ func (b *Backend) secretAccessTokenRevoke(ctx context.Context, req *logical.Requ } } - Event(ctx, b.Backend, "token-revoke", map[string]string{ + event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "token-revoke", map[string]string{ "lease_id": secret.LeaseID, "path": req.Secret.InternalData["path"].(string), "name": req.Secret.InternalData["name"].(string), From 97be25b11bbdd8942bc247e6df8f145a84f85fa2 Mon Sep 17 00:00:00 2001 From: Ilija Matoski Date: Mon, 16 Jun 2025 18:12:59 +0200 Subject: [PATCH 08/17] moved token scope to token pkg --- gitlab_client_test.go | 6 +- internal/errs/errs.go | 4 + internal/token/scope.go | 160 ++++++++++++++++++ internal/token/scope_test.go | 91 ++++++++++ internal/token/type.go | 7 +- internal/token/type_test.go | 3 +- name_tpl_rand_string_test.go | 2 +- name_tpl_test.go | 8 +- name_tpl_unix_timestamp_test.go | 2 +- path_role.go | 16 +- path_role_deploy_tokens_test.go | 4 +- ...ole_pipeline_project_trigger_token_test.go | 2 +- path_role_test.go | 28 +-- path_role_ttl_test.go | 12 +- path_token_role.go | 2 +- path_token_role_multiple_config_test.go | 8 +- type_token_scope.go | 160 ------------------ type_token_scope_test.go | 90 ---------- ...dmin_user_pat_gitlab_revokes_token_test.go | 2 +- ...admin_user_pat_vault_revokes_token_test.go | 2 +- with_group_deploy_token_test.go | 2 +- with_normal_user_gat_test.go | 2 +- with_normal_user_personal_at_fails_test.go | 2 +- with_normal_user_project_at_test.go | 2 +- with_project_deploy_token_test.go | 2 +- with_service_account_fail_test.go | 2 +- with_service_account_group_test.go | 2 +- with_service_account_user_test.go | 2 +- 28 files changed, 315 insertions(+), 310 deletions(-) create mode 100644 internal/token/scope.go create mode 100644 internal/token/scope_test.go delete mode 100644 type_token_scope.go delete mode 100644 type_token_scope_test.go diff --git a/gitlab_client_test.go b/gitlab_client_test.go index e0bed6a..1a9801d 100644 --- a/gitlab_client_test.go +++ b/gitlab_client_test.go @@ -257,7 +257,7 @@ func TestGitlabClient_CreateAccessToken_And_Revoke(t *testing.T) { "example", "name", timeExpiresAt, - []string{gitlab.TokenScopeReadApi.String()}, + []string{token2.ScopeReadApi.String()}, gitlab.AccessLevelGuestPermissions, ) require.NoError(t, err) @@ -271,7 +271,7 @@ func TestGitlabClient_CreateAccessToken_And_Revoke(t *testing.T) { "example/example", "name", timeExpiresAt, - []string{gitlab.TokenScopeReadApi.String()}, + []string{token2.ScopeReadApi.String()}, gitlab.AccessLevelDeveloperPermissions, ) require.NoError(t, err) @@ -286,7 +286,7 @@ func TestGitlabClient_CreateAccessToken_And_Revoke(t *testing.T) { 1, "name", timeExpiresAt, - []string{gitlab.TokenScopeReadApi.String()}, + []string{token2.ScopeReadApi.String()}, ) require.NoError(t, err) require.NotNil(t, patToken) diff --git a/internal/errs/errs.go b/internal/errs/errs.go index ccb4f41..6d5084d 100644 --- a/internal/errs/errs.go +++ b/internal/errs/errs.go @@ -17,4 +17,8 @@ var ( // ErrBackendNotConfigured represents an error when trying to use a backend that hasn't been properly configured ErrBackendNotConfigured = errors.New("backend not configured") + + ErrUnknownTokenType = errors.New("unknown token type") + + ErrUnknownTokenScope = errors.New("unknown token scope") ) diff --git a/internal/token/scope.go b/internal/token/scope.go new file mode 100644 index 0000000..f59d883 --- /dev/null +++ b/internal/token/scope.go @@ -0,0 +1,160 @@ +package token + +import ( + "fmt" + "slices" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" +) + +type Scope string + +const ( + // ScopeApi grants complete read/write access to the API, including all groups and projects, the container registry, the dependency proxy, and the package registry. Also grants complete read/write access to the registry and repository using Git over HTTP + ScopeApi = Scope("api") + // ScopeReadApi grants read access to the scoped group and related project API, including the Package Registry + ScopeReadApi = Scope("read_api") + // ScopeReadRegistry grants read access (pull) to the Container Registry images if any project within expected group is private and authorization is required. + ScopeReadRegistry = Scope("read_registry") + // ScopeWriteRegistry grants write access (push) to the Container Registry. + ScopeWriteRegistry = Scope("write_registry") + // ScopeReadRepository grants read access (pull) to the Container Registry images if any project within expected group is private and authorization is required + ScopeReadRepository = Scope("read_repository") + // ScopeWriteRepository grants read and write access (pull and push) to all repositories within expected group + ScopeWriteRepository = Scope("write_repository") + + // ScopeReadPackageRegistry Allows read-only access to the package registry. + ScopeReadPackageRegistry = Scope("read_package_registry") + // ScopeWritePackageRegistry Allows read and write access to the package registry. + ScopeWritePackageRegistry = Scope("write_package_registry") + + // ScopeCreateRunner grants permission to create runners in expected group + ScopeCreateRunner = Scope("create_runner") + // ScopeManageRunner grants permission to manage runners in expected group + ScopeManageRunner = Scope("manage_runner") + + // ScopeReadUser grants read-only access to the authenticated user’s profile through the /user API endpoint, which includes username, public email, and full name. Also grants access to read-only API endpoints under /users. + ScopeReadUser = Scope("read_user") + // ScopeSudo grants permission to perform API actions as any user in the system, when authenticated as an administrator. + ScopeSudo = Scope("sudo") + // ScopeAdminMode grants permission to perform API actions as an administrator, when Admin Mode is enabled. + ScopeAdminMode = Scope("admin_mode") + + // ScopeAiFeatures grants permission to perform API actions for GitLab Duo. This scope is designed to work with the GitLab Duo Plugin for JetBrains. For all other extensions, see scope requirements. + ScopeAiFeatures = Scope("ai_features") + // ScopeK8SProxy grants permission to perform Kubernetes API calls using the agent for Kubernetes. + ScopeK8SProxy = Scope("k8s_proxy") + // ScopeReadServicePing grant access to download Service Ping payload through the API when authenticated as an admin use. + ScopeReadServicePing = Scope("read_service_ping") + + // ScopeSelfRotate grants permission to rotate this token using the personal access token API. Does not allow rotation of other tokens. + ScopeSelfRotate = Scope("self_rotate") + // ScopeReadVirtualRegistry if a project is private and authorization is required, grants read-only (pull) access to container images through the dependency proxy. Available only when the dependency proxy is enabled. + ScopeReadVirtualRegistry = Scope("read_virtual_registry") + // ScopeWriteVirtualRegistry if a project is private and authorization is required, grants read (pull), write (push), and delete access to container images through the dependency proxy. Available only when the dependency proxy is enabled. + ScopeWriteVirtualRegistry = Scope("write_virtual_registry") + + ScopeUnknown = Scope("") +) + +var ( + + // ValidPersonalTokenScopes defines the actions you can perform when you authenticate with a project access token. + ValidPersonalTokenScopes = []string{ + ScopeApi.String(), + ScopeReadUser.String(), + ScopeReadApi.String(), + ScopeReadRepository.String(), + ScopeWriteRepository.String(), + ScopeReadRegistry.String(), + ScopeWriteRegistry.String(), + ScopeReadVirtualRegistry.String(), + ScopeWriteVirtualRegistry.String(), + ScopeSudo.String(), + ScopeAdminMode.String(), + ScopeCreateRunner.String(), + ScopeManageRunner.String(), + ScopeAiFeatures.String(), + ScopeK8SProxy.String(), + ScopeSelfRotate.String(), + ScopeReadServicePing.String(), + } + + ValidProjectTokenScopes = []string{ + ScopeApi.String(), + ScopeReadApi.String(), + ScopeReadRegistry.String(), + ScopeWriteRegistry.String(), + ScopeReadRepository.String(), + ScopeWriteRepository.String(), + ScopeCreateRunner.String(), + ScopeManageRunner.String(), + ScopeAiFeatures.String(), + ScopeK8SProxy.String(), + ScopeSelfRotate.String(), + } + + ValidGroupTokenScopes = []string{ + ScopeApi.String(), + ScopeReadApi.String(), + ScopeReadRegistry.String(), + ScopeWriteRegistry.String(), + ScopeReadVirtualRegistry.String(), + ScopeWriteVirtualRegistry.String(), + ScopeReadRepository.String(), + ScopeWriteRepository.String(), + ScopeCreateRunner.String(), + ScopeManageRunner.String(), + ScopeAiFeatures.String(), + ScopeK8SProxy.String(), + ScopeSelfRotate.String(), + } + + ValidUserServiceAccountTokenScopes = ValidPersonalTokenScopes + + ValidGroupServiceAccountTokenScopes = ValidGroupTokenScopes + + ValidPipelineProjectTokenScopes []string + + ValidProjectDeployTokenScopes = []string{ + ScopeReadRepository.String(), + ScopeReadRegistry.String(), + ScopeWriteRegistry.String(), + ScopeReadVirtualRegistry.String(), + ScopeWriteVirtualRegistry.String(), + ScopeReadPackageRegistry.String(), + ScopeWritePackageRegistry.String(), + } + + ValidGroupDeployTokenScopes = []string{ + ScopeReadRepository.String(), + ScopeReadRegistry.String(), + ScopeWriteRegistry.String(), + ScopeReadVirtualRegistry.String(), + ScopeWriteVirtualRegistry.String(), + ScopeReadPackageRegistry.String(), + ScopeWritePackageRegistry.String(), + } +) + +func (i Scope) String() string { + return string(i) +} + +func (i Scope) Value() string { + return i.String() +} + +func ScopeParse(value string) (Scope, error) { + if slices.Contains(ValidGroupTokenScopes, value) || + slices.Contains(ValidPipelineProjectTokenScopes, value) || + slices.Contains(ValidGroupDeployTokenScopes, value) || + slices.Contains(ValidProjectDeployTokenScopes, value) || + slices.Contains(ValidPersonalTokenScopes, value) || + slices.Contains(ValidProjectTokenScopes, value) || + slices.Contains(ValidUserServiceAccountTokenScopes, value) || + slices.Contains(ValidGroupServiceAccountTokenScopes, value) { + return Scope(value), nil + } + return ScopeUnknown, fmt.Errorf("failed to parse '%s': %w", value, errs.ErrUnknownTokenScope) +} diff --git a/internal/token/scope_test.go b/internal/token/scope_test.go new file mode 100644 index 0000000..3385858 --- /dev/null +++ b/internal/token/scope_test.go @@ -0,0 +1,91 @@ +//go:build unit + +package token_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" +) + +func TestTokenScope(t *testing.T) { + var tests = []struct { + expected token.Scope + input string + err bool + }{ + { + expected: token.ScopeApi, + input: token.ScopeApi.String(), + }, + { + expected: token.ScopeReadApi, + input: token.ScopeReadApi.String(), + }, + { + expected: token.ScopeReadRegistry, + input: token.ScopeReadRegistry.String(), + }, + { + expected: token.ScopeWriteRegistry, + input: token.ScopeWriteRegistry.String(), + }, + { + expected: token.ScopeReadRepository, + input: token.ScopeReadRepository.String(), + }, + { + expected: token.ScopeWriteRepository, + input: token.ScopeWriteRepository.String(), + }, + { + expected: token.ScopeCreateRunner, + input: token.ScopeCreateRunner.String(), + }, + { + expected: token.ScopeReadUser, + input: token.ScopeReadUser.String(), + }, + { + expected: token.ScopeSudo, + input: token.ScopeSudo.String(), + }, + { + expected: token.ScopeAdminMode, + input: token.ScopeAdminMode.String(), + }, + { + expected: token.ScopeReadPackageRegistry, + input: token.ScopeReadPackageRegistry.String(), + }, + { + expected: token.ScopeWritePackageRegistry, + input: token.ScopeWritePackageRegistry.String(), + }, + { + expected: token.ScopeUnknown, + input: "what", + err: true, + }, + { + expected: token.ScopeUnknown, + input: "unknown", + err: true, + }, + } + + for _, test := range tests { + t.Logf("assert parse(%s) = %s (err: %v)", test.input, test.expected, test.err) + val, err := token.ScopeParse(test.input) + assert.EqualValues(t, test.expected, val) + assert.EqualValues(t, test.expected.Value(), test.expected.String()) + if test.err { + assert.ErrorIs(t, err, errs.ErrUnknownTokenScope) + } else { + assert.NoError(t, err) + } + } +} diff --git a/internal/token/type.go b/internal/token/type.go index 421a9c5..6e37ef6 100644 --- a/internal/token/type.go +++ b/internal/token/type.go @@ -1,9 +1,10 @@ package token import ( - "errors" "fmt" "slices" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" ) type Type string @@ -22,8 +23,6 @@ const ( ) var ( - ErrUnknownTokenType = errors.New("unknown token type") - ValidTokenTypes = []string{ TypePersonal.String(), TypeProject.String(), @@ -48,5 +47,5 @@ func TypeParse(value string) (Type, error) { if slices.Contains(ValidTokenTypes, value) { return Type(value), nil } - return TypeUnknown, fmt.Errorf("failed to parse '%s': %w", value, ErrUnknownTokenType) + return TypeUnknown, fmt.Errorf("failed to parse '%s': %w", value, errs.ErrUnknownTokenType) } diff --git a/internal/token/type_test.go b/internal/token/type_test.go index 414bb32..526ed58 100644 --- a/internal/token/type_test.go +++ b/internal/token/type_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/assert" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) @@ -66,7 +67,7 @@ func TestTokenType(t *testing.T) { assert.EqualValues(t, test.expected, val) assert.EqualValues(t, test.expected.Value(), test.expected.String()) if test.err { - assert.ErrorIs(t, err, token.ErrUnknownTokenType) + assert.ErrorIs(t, err, errs.ErrUnknownTokenType) } else { assert.NoError(t, err) } diff --git a/name_tpl_rand_string_test.go b/name_tpl_rand_string_test.go index db2d49e..03922d3 100644 --- a/name_tpl_rand_string_test.go +++ b/name_tpl_rand_string_test.go @@ -19,7 +19,7 @@ func TestTokenNameGenerator_RandString(t *testing.T) { TTL: time.Hour, Path: "/path", Name: "{{ randHexString 8 }}", - Scopes: []string{g.TokenScopeApi.String()}, + Scopes: []string{token.ScopeApi.String()}, AccessLevel: g.AccessLevelNoPermissions, TokenType: token.TypePersonal, GitlabRevokesTokens: false, diff --git a/name_tpl_test.go b/name_tpl_test.go index e56ccaf..32ae505 100644 --- a/name_tpl_test.go +++ b/name_tpl_test.go @@ -28,7 +28,7 @@ func TestTokenNameGenerator(t *testing.T) { TTL: time.Hour, Path: "/path", Name: "{{ .role_name", - Scopes: []string{g.TokenScopeApi.String()}, + Scopes: []string{token.ScopeApi.String()}, AccessLevel: g.AccessLevelNoPermissions, TokenType: token.TypePersonal, GitlabRevokesTokens: true, @@ -44,7 +44,7 @@ func TestTokenNameGenerator(t *testing.T) { TTL: time.Hour, Path: "/path", Name: "{{ .role_name }}-{{ .token_type }}-access-token-{{ yesNoBool .gitlab_revokes_token }}", - Scopes: []string{g.TokenScopeApi.String()}, + Scopes: []string{token.ScopeApi.String()}, AccessLevel: g.AccessLevelNoPermissions, TokenType: token.TypePersonal, GitlabRevokesTokens: true, @@ -60,7 +60,7 @@ func TestTokenNameGenerator(t *testing.T) { TTL: time.Hour, Path: "/path", Name: "{{ .role_name }}-{{ .token_type }}-{{ stringsJoin .scopes \"-\" }}-{{ yesNoBool .gitlab_revokes_token }}", - Scopes: []string{g.TokenScopeApi.String(), g.TokenScopeSudo.String()}, + Scopes: []string{token.ScopeApi.String(), token.ScopeSudo.String()}, AccessLevel: g.AccessLevelNoPermissions, TokenType: token.TypePersonal, GitlabRevokesTokens: false, @@ -76,7 +76,7 @@ func TestTokenNameGenerator(t *testing.T) { TTL: time.Hour, Path: "/path", Name: "{{ .role_name }}-{{ .token_type }}-{{ timeNowFormat \"2006-01\" }}", - Scopes: []string{g.TokenScopeApi.String(), g.TokenScopeSudo.String()}, + Scopes: []string{token.ScopeApi.String(), token.ScopeSudo.String()}, AccessLevel: g.AccessLevelNoPermissions, TokenType: token.TypePersonal, GitlabRevokesTokens: false, diff --git a/name_tpl_unix_timestamp_test.go b/name_tpl_unix_timestamp_test.go index 28eca4d..3085f3b 100644 --- a/name_tpl_unix_timestamp_test.go +++ b/name_tpl_unix_timestamp_test.go @@ -21,7 +21,7 @@ func TestTokenNameGenerator_UnixTimeStamp(t *testing.T) { TTL: time.Hour, Path: "/path", Name: "{{ .unix_timestamp_utc }}", - Scopes: []string{g.TokenScopeApi.String()}, + Scopes: []string{token.ScopeApi.String()}, AccessLevel: g.AccessLevelNoPermissions, TokenType: token.TypePersonal, GitlabRevokesTokens: false, diff --git a/path_role.go b/path_role.go index 0c2049d..2d35c29 100644 --- a/path_role.go +++ b/path_role.go @@ -60,7 +60,7 @@ var ( DisplayAttrs: &framework.DisplayAttributes{ Name: "Scopes", }, - AllowedValues: utils.ToAny(ValidPersonalTokenScopes...), + AllowedValues: utils.ToAny(token.ValidPersonalTokenScopes...), }, "ttl": { Type: framework.TypeDurationSecond, @@ -254,27 +254,27 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data switch tokenType { case token.TypePersonal: validAccessLevels = ValidPersonalAccessLevels - validScopes = ValidPersonalTokenScopes + validScopes = token.ValidPersonalTokenScopes noEmptyScopes = false skipFields = []string{"config_name", "access_level"} case token.TypeGroup: validAccessLevels = ValidGroupAccessLevels - validScopes = ValidGroupTokenScopes + validScopes = token.ValidGroupTokenScopes noEmptyScopes = false skipFields = []string{"config_name"} case token.TypeProject: validAccessLevels = ValidProjectAccessLevels - validScopes = ValidProjectTokenScopes + validScopes = token.ValidProjectTokenScopes noEmptyScopes = false skipFields = []string{"config_name"} case token.TypeUserServiceAccount: validAccessLevels = ValidUserServiceAccountAccessLevels - validScopes = ValidUserServiceAccountTokenScopes + validScopes = token.ValidUserServiceAccountTokenScopes noEmptyScopes = false skipFields = []string{"config_name", "access_level"} case token.TypeGroupServiceAccount: validAccessLevels = ValidGroupServiceAccountAccessLevels - validScopes = ValidGroupServiceAccountTokenScopes + validScopes = token.ValidGroupServiceAccountTokenScopes noEmptyScopes = false skipFields = []string{"config_name", "access_level"} case token.TypePipelineProjectTrigger: @@ -284,12 +284,12 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data skipFields = []string{"config_name", "access_level", "scopes"} case token.TypeProjectDeploy: validAccessLevels = ValidProjectDeployAccessLevels - validScopes = ValidProjectDeployTokenScopes + validScopes = token.ValidProjectDeployTokenScopes noEmptyScopes = true skipFields = []string{"config_name", "access_level"} case token.TypeGroupDeploy: validAccessLevels = ValidGroupDeployAccessLevels - validScopes = ValidGroupDeployTokenScopes + validScopes = token.ValidGroupDeployTokenScopes noEmptyScopes = true skipFields = []string{"config_name", "access_level"} } diff --git a/path_role_deploy_tokens_test.go b/path_role_deploy_tokens_test.go index 1b7828c..a2175d6 100644 --- a/path_role_deploy_tokens_test.go +++ b/path_role_deploy_tokens_test.go @@ -38,12 +38,12 @@ func TestPathRolesDeployTokens(t *testing.T) { { tokenType: token.TypeProjectDeploy, path: "example/example", - scopes: []string{gitlab.TokenScopeReadRepository.String()}, + scopes: []string{token.ScopeReadRepository.String()}, }, { tokenType: token.TypeGroupDeploy, path: "test/test1", - scopes: []string{gitlab.TokenScopeReadRepository.String()}, + scopes: []string{token.ScopeReadRepository.String()}, }, } diff --git a/path_role_pipeline_project_trigger_token_test.go b/path_role_pipeline_project_trigger_token_test.go index 9479656..c0459e0 100644 --- a/path_role_pipeline_project_trigger_token_test.go +++ b/path_role_pipeline_project_trigger_token_test.go @@ -39,7 +39,7 @@ func TestPathRolesPipelineProjectTrigger(t *testing.T) { "name": "Example user personal token", "access_level": gitlab.AccessLevelNoPermissions.String(), "token_type": token.TypePipelineProjectTrigger.String(), - "scopes": []string{gitlab.TokenScopeApi.String()}, + "scopes": []string{token.ScopeApi.String()}, "ttl": "1h", }, }) diff --git a/path_role_test.go b/path_role_test.go index e51c85b..3208f36 100644 --- a/path_role_test.go +++ b/path_role_test.go @@ -83,7 +83,7 @@ func TestPathRoles(t *testing.T) { "name": token.TypePersonal.String(), "token_type": token.TypePersonal.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, - "scopes": gitlab.ValidPersonalTokenScopes, + "scopes": token.ValidPersonalTokenScopes, "gitlab_revokes_token": false, }, }) @@ -105,7 +105,7 @@ func TestPathRoles(t *testing.T) { "access_level": gitlab.AccessLevelOwnerPermissions.String(), "token_type": token.TypePersonal.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, - "scopes": gitlab.ValidPersonalTokenScopes, + "scopes": token.ValidPersonalTokenScopes, "gitlab_revokes_token": false, }, }) @@ -128,7 +128,7 @@ func TestPathRoles(t *testing.T) { "name": token.TypeProject.String(), "token_type": token.TypeProject.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, - "scopes": gitlab.ValidProjectTokenScopes, + "scopes": token.ValidProjectTokenScopes, "gitlab_revokes_token": false, }, }) @@ -149,7 +149,7 @@ func TestPathRoles(t *testing.T) { "access_level": gitlab.AccessLevelOwnerPermissions.String(), "token_type": token.TypeProject.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, - "scopes": gitlab.ValidProjectTokenScopes, + "scopes": token.ValidProjectTokenScopes, "gitlab_revokes_token": false, }, }) @@ -173,7 +173,7 @@ func TestPathRoles(t *testing.T) { "name": token.TypeGroup.String(), "token_type": token.TypeGroup.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, - "scopes": gitlab.ValidGroupTokenScopes, + "scopes": token.ValidGroupTokenScopes, "gitlab_revokes_token": false, }, }) @@ -194,7 +194,7 @@ func TestPathRoles(t *testing.T) { "access_level": gitlab.AccessLevelOwnerPermissions.String(), "token_type": token.TypeGroup.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, - "scopes": gitlab.ValidGroupTokenScopes, + "scopes": token.ValidGroupTokenScopes, "gitlab_revokes_token": false, }, }) @@ -237,7 +237,7 @@ func TestPathRoles(t *testing.T) { "name": "{{ . } invalid template", "token_type": token.TypePersonal.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, - "scopes": gitlab.ValidPersonalTokenScopes, + "scopes": token.ValidPersonalTokenScopes, "gitlab_revokes_token": false, }, }) @@ -261,7 +261,7 @@ func TestPathRoles(t *testing.T) { "access_level": gitlab.AccessLevelOwnerPermissions.String(), "ttl": "48h", "token_type": token.TypeProject.String(), - "scopes": gitlab.ValidProjectTokenScopes, + "scopes": token.ValidProjectTokenScopes, }, }) require.NoError(t, err) @@ -282,7 +282,7 @@ func TestPathRoles(t *testing.T) { "access_level": gitlab.AccessLevelOwnerPermissions.String(), "token_type": token.TypeProject.String(), "ttl": "48h", - "scopes": gitlab.ValidPersonalTokenScopes, + "scopes": token.ValidPersonalTokenScopes, "gitlab_revokes_token": false, }, }) @@ -306,7 +306,7 @@ func TestPathRoles(t *testing.T) { "name": "Example user personal token", "ttl": "48h", "token_type": token.TypePersonal.String(), - "scopes": gitlab.ValidPersonalTokenScopes, + "scopes": token.ValidPersonalTokenScopes, }, }) require.NoError(t, err) @@ -351,7 +351,7 @@ func TestPathRoles(t *testing.T) { "ttl": "48h", "access_level": gitlab.AccessLevelOwnerPermissions.String(), "token_type": token.TypeGroup.String(), - "scopes": gitlab.ValidProjectTokenScopes, + "scopes": token.ValidProjectTokenScopes, }, }) require.NoError(t, err) @@ -371,7 +371,7 @@ func TestPathRoles(t *testing.T) { "name": "Example user personal token", "access_level": gitlab.AccessLevelOwnerPermissions.String(), "token_type": token.TypeGroup.String(), - "scopes": gitlab.ValidPersonalTokenScopes, + "scopes": token.ValidPersonalTokenScopes, }, }) require.Error(t, err) @@ -424,8 +424,8 @@ func TestPathRoles(t *testing.T) { "ttl": int64((5 * 24 * time.Hour).Seconds()), "gitlab_revokes_token": false, "scopes": []string{ - gitlab.TokenScopeApi.String(), - gitlab.TokenScopeReadRegistry.String(), + token.ScopeApi.String(), + token.ScopeReadRegistry.String(), }, } diff --git a/path_role_ttl_test.go b/path_role_ttl_test.go index 27332d7..82660a7 100644 --- a/path_role_ttl_test.go +++ b/path_role_ttl_test.go @@ -32,8 +32,8 @@ func TestPathRolesTTL(t *testing.T) { "name": "Example user personal token", "token_type": token.TypePersonal.String(), "scopes": []string{ - gitlab.TokenScopeApi.String(), - gitlab.TokenScopeReadRegistry.String(), + token.ScopeApi.String(), + token.ScopeReadRegistry.String(), }, "gitlab_revokes_token": false, } @@ -93,8 +93,8 @@ func TestPathRolesTTL(t *testing.T) { "name": "Example user personal token", "token_type": token.TypePersonal.String(), "scopes": []string{ - gitlab.TokenScopeApi.String(), - gitlab.TokenScopeReadRegistry.String(), + token.ScopeApi.String(), + token.ScopeReadRegistry.String(), }, "gitlab_revokes_token": false, } @@ -155,8 +155,8 @@ func TestPathRolesTTL(t *testing.T) { "name": "Example user personal token", "token_type": token.TypePersonal.String(), "scopes": []string{ - gitlab.TokenScopeApi.String(), - gitlab.TokenScopeReadRegistry.String(), + token.ScopeApi.String(), + token.ScopeReadRegistry.String(), }, "gitlab_revokes_token": true, } diff --git a/path_token_role.go b/path_token_role.go index dc6c886..e41c72b 100644 --- a/path_token_role.go +++ b/path_token_role.go @@ -129,7 +129,7 @@ func (b *Backend) pathTokenRoleCreate(ctx context.Context, req *logical.Request, token, err = client.CreatePipelineProjectTriggerAccessToken(ctx, role.Path, name, projectId, name, &expiresAt) } default: - return logical.ErrorResponse("invalid token type"), fmt.Errorf("%s: %w", role.TokenType.String(), token2.ErrUnknownTokenType) + return logical.ErrorResponse("invalid token type"), fmt.Errorf("%s: %w", role.TokenType.String(), errs.ErrUnknownTokenType) } if err != nil || token == nil { diff --git a/path_token_role_multiple_config_test.go b/path_token_role_multiple_config_test.go index 74cf64f..1b5c1d4 100644 --- a/path_token_role_multiple_config_test.go +++ b/path_token_role_multiple_config_test.go @@ -56,14 +56,14 @@ func TestPathTokenRolesMultipleConfigs(t *testing.T) { roleName: "root-root", path: "root", tokenType: token.TypePersonal, - scopes: []string{gitlab.TokenScopeApi.String(), gitlab.TokenScopeSelfRotate.String()}, + scopes: []string{token.ScopeApi.String(), token.ScopeSelfRotate.String()}, tokenName: "admin_user_root", }, { roleName: "root-normal-user", path: "normal-user", tokenType: token.TypePersonal, - scopes: []string{gitlab.TokenScopeApi.String(), gitlab.TokenScopeSelfRotate.String()}, + scopes: []string{token.ScopeApi.String(), token.ScopeSelfRotate.String()}, tokenName: "admin_user_root", }, }, @@ -73,7 +73,7 @@ func TestPathTokenRolesMultipleConfigs(t *testing.T) { path: "example/example", tokenType: token.TypeProject, accessLevel: gitlab.AccessLevelGuestPermissions, - scopes: []string{gitlab.TokenScopeApi.String(), gitlab.TokenScopeSelfRotate.String()}, + scopes: []string{token.ScopeApi.String(), token.ScopeSelfRotate.String()}, tokenName: "admin_user_initial_token", }, }, @@ -83,7 +83,7 @@ func TestPathTokenRolesMultipleConfigs(t *testing.T) { path: "example", tokenType: token.TypeGroup, accessLevel: gitlab.AccessLevelGuestPermissions, - scopes: []string{gitlab.TokenScopeApi.String(), gitlab.TokenScopeSelfRotate.String()}, + scopes: []string{token.ScopeApi.String(), token.ScopeSelfRotate.String()}, tokenName: "normal_user_initial_token", }, }, diff --git a/type_token_scope.go b/type_token_scope.go deleted file mode 100644 index 7687777..0000000 --- a/type_token_scope.go +++ /dev/null @@ -1,160 +0,0 @@ -package gitlab - -import ( - "errors" - "fmt" - "slices" -) - -type TokenScope string - -const ( - // TokenScopeApi grants complete read/write access to the API, including all groups and projects, the container registry, the dependency proxy, and the package registry. Also grants complete read/write access to the registry and repository using Git over HTTP - TokenScopeApi = TokenScope("api") - // TokenScopeReadApi grants read access to the scoped group and related project API, including the Package Registry - TokenScopeReadApi = TokenScope("read_api") - // TokenScopeReadRegistry grants read access (pull) to the Container Registry images if any project within expected group is private and authorization is required. - TokenScopeReadRegistry = TokenScope("read_registry") - // TokenScopeWriteRegistry grants write access (push) to the Container Registry. - TokenScopeWriteRegistry = TokenScope("write_registry") - // TokenScopeReadRepository grants read access (pull) to the Container Registry images if any project within expected group is private and authorization is required - TokenScopeReadRepository = TokenScope("read_repository") - // TokenScopeWriteRepository grants read and write access (pull and push) to all repositories within expected group - TokenScopeWriteRepository = TokenScope("write_repository") - - // TokenScopeReadPackageRegistry Allows read-only access to the package registry. - TokenScopeReadPackageRegistry = TokenScope("read_package_registry") - // TokenScopeWritePackageRegistry Allows read and write access to the package registry. - TokenScopeWritePackageRegistry = TokenScope("write_package_registry") - - // TokenScopeCreateRunner grants permission to create runners in expected group - TokenScopeCreateRunner = TokenScope("create_runner") - // TokenScopeManageRunner grants permission to manage runners in expected group - TokenScopeManageRunner = TokenScope("manage_runner") - - // TokenScopeReadUser grants read-only access to the authenticated user’s profile through the /user API endpoint, which includes username, public email, and full name. Also grants access to read-only API endpoints under /users. - TokenScopeReadUser = TokenScope("read_user") - // TokenScopeSudo grants permission to perform API actions as any user in the system, when authenticated as an administrator. - TokenScopeSudo = TokenScope("sudo") - // TokenScopeAdminMode grants permission to perform API actions as an administrator, when Admin Mode is enabled. - TokenScopeAdminMode = TokenScope("admin_mode") - - // TokenScopeAiFeatures grants permission to perform API actions for GitLab Duo. This scope is designed to work with the GitLab Duo Plugin for JetBrains. For all other extensions, see scope requirements. - TokenScopeAiFeatures = TokenScope("ai_features") - // TokenScopeK8SProxy grants permission to perform Kubernetes API calls using the agent for Kubernetes. - TokenScopeK8SProxy = TokenScope("k8s_proxy") - // TokenScopeReadServicePing grant access to download Service Ping payload through the API when authenticated as an admin use. - TokenScopeReadServicePing = TokenScope("read_service_ping") - - // TokenScopeSelfRotate grants permission to rotate this token using the personal access token API. Does not allow rotation of other tokens. - TokenScopeSelfRotate = TokenScope("self_rotate") - // TokenScopeReadVirtualRegistry if a project is private and authorization is required, grants read-only (pull) access to container images through the dependency proxy. Available only when the dependency proxy is enabled. - TokenScopeReadVirtualRegistry = TokenScope("read_virtual_registry") - // TokenScopeWriteVirtualRegistry if a project is private and authorization is required, grants read (pull), write (push), and delete access to container images through the dependency proxy. Available only when the dependency proxy is enabled. - TokenScopeWriteVirtualRegistry = TokenScope("write_virtual_registry") - - TokenScopeUnknown = TokenScope("") -) - -var ( - ErrUnknownTokenScope = errors.New("unknown token scope") - - // ValidPersonalTokenScopes defines the actions you can perform when you authenticate with a project access token. - ValidPersonalTokenScopes = []string{ - TokenScopeApi.String(), - TokenScopeReadUser.String(), - TokenScopeReadApi.String(), - TokenScopeReadRepository.String(), - TokenScopeWriteRepository.String(), - TokenScopeReadRegistry.String(), - TokenScopeWriteRegistry.String(), - TokenScopeReadVirtualRegistry.String(), - TokenScopeWriteVirtualRegistry.String(), - TokenScopeSudo.String(), - TokenScopeAdminMode.String(), - TokenScopeCreateRunner.String(), - TokenScopeManageRunner.String(), - TokenScopeAiFeatures.String(), - TokenScopeK8SProxy.String(), - TokenScopeSelfRotate.String(), - TokenScopeReadServicePing.String(), - } - - ValidProjectTokenScopes = []string{ - TokenScopeApi.String(), - TokenScopeReadApi.String(), - TokenScopeReadRegistry.String(), - TokenScopeWriteRegistry.String(), - TokenScopeReadRepository.String(), - TokenScopeWriteRepository.String(), - TokenScopeCreateRunner.String(), - TokenScopeManageRunner.String(), - TokenScopeAiFeatures.String(), - TokenScopeK8SProxy.String(), - TokenScopeSelfRotate.String(), - } - - ValidGroupTokenScopes = []string{ - TokenScopeApi.String(), - TokenScopeReadApi.String(), - TokenScopeReadRegistry.String(), - TokenScopeWriteRegistry.String(), - TokenScopeReadVirtualRegistry.String(), - TokenScopeWriteVirtualRegistry.String(), - TokenScopeReadRepository.String(), - TokenScopeWriteRepository.String(), - TokenScopeCreateRunner.String(), - TokenScopeManageRunner.String(), - TokenScopeAiFeatures.String(), - TokenScopeK8SProxy.String(), - TokenScopeSelfRotate.String(), - } - - ValidUserServiceAccountTokenScopes = ValidPersonalTokenScopes - - ValidGroupServiceAccountTokenScopes = ValidGroupTokenScopes - - ValidPipelineProjectTokenScopes []string - - ValidProjectDeployTokenScopes = []string{ - TokenScopeReadRepository.String(), - TokenScopeReadRegistry.String(), - TokenScopeWriteRegistry.String(), - TokenScopeReadVirtualRegistry.String(), - TokenScopeWriteVirtualRegistry.String(), - TokenScopeReadPackageRegistry.String(), - TokenScopeWritePackageRegistry.String(), - } - - ValidGroupDeployTokenScopes = []string{ - TokenScopeReadRepository.String(), - TokenScopeReadRegistry.String(), - TokenScopeWriteRegistry.String(), - TokenScopeReadVirtualRegistry.String(), - TokenScopeWriteVirtualRegistry.String(), - TokenScopeReadPackageRegistry.String(), - TokenScopeWritePackageRegistry.String(), - } -) - -func (i TokenScope) String() string { - return string(i) -} - -func (i TokenScope) Value() string { - return i.String() -} - -func TokenScopeParse(value string) (TokenScope, error) { - if slices.Contains(ValidGroupTokenScopes, value) || - slices.Contains(ValidPipelineProjectTokenScopes, value) || - slices.Contains(ValidGroupDeployTokenScopes, value) || - slices.Contains(ValidProjectDeployTokenScopes, value) || - slices.Contains(ValidPersonalTokenScopes, value) || - slices.Contains(ValidProjectTokenScopes, value) || - slices.Contains(ValidUserServiceAccountTokenScopes, value) || - slices.Contains(ValidGroupServiceAccountTokenScopes, value) { - return TokenScope(value), nil - } - return TokenScopeUnknown, fmt.Errorf("failed to parse '%s': %w", value, ErrUnknownTokenScope) -} diff --git a/type_token_scope_test.go b/type_token_scope_test.go deleted file mode 100644 index fa0614c..0000000 --- a/type_token_scope_test.go +++ /dev/null @@ -1,90 +0,0 @@ -//go:build unit - -package gitlab_test - -import ( - "testing" - - "github.com/stretchr/testify/assert" - - gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" -) - -func TestTokenScope(t *testing.T) { - var tests = []struct { - expected gitlab.TokenScope - input string - err bool - }{ - { - expected: gitlab.TokenScopeApi, - input: gitlab.TokenScopeApi.String(), - }, - { - expected: gitlab.TokenScopeReadApi, - input: gitlab.TokenScopeReadApi.String(), - }, - { - expected: gitlab.TokenScopeReadRegistry, - input: gitlab.TokenScopeReadRegistry.String(), - }, - { - expected: gitlab.TokenScopeWriteRegistry, - input: gitlab.TokenScopeWriteRegistry.String(), - }, - { - expected: gitlab.TokenScopeReadRepository, - input: gitlab.TokenScopeReadRepository.String(), - }, - { - expected: gitlab.TokenScopeWriteRepository, - input: gitlab.TokenScopeWriteRepository.String(), - }, - { - expected: gitlab.TokenScopeCreateRunner, - input: gitlab.TokenScopeCreateRunner.String(), - }, - { - expected: gitlab.TokenScopeReadUser, - input: gitlab.TokenScopeReadUser.String(), - }, - { - expected: gitlab.TokenScopeSudo, - input: gitlab.TokenScopeSudo.String(), - }, - { - expected: gitlab.TokenScopeAdminMode, - input: gitlab.TokenScopeAdminMode.String(), - }, - { - expected: gitlab.TokenScopeReadPackageRegistry, - input: gitlab.TokenScopeReadPackageRegistry.String(), - }, - { - expected: gitlab.TokenScopeWritePackageRegistry, - input: gitlab.TokenScopeWritePackageRegistry.String(), - }, - { - expected: gitlab.TokenScopeUnknown, - input: "what", - err: true, - }, - { - expected: gitlab.TokenScopeUnknown, - input: "unknown", - err: true, - }, - } - - for _, test := range tests { - t.Logf("assert parse(%s) = %s (err: %v)", test.input, test.expected, test.err) - val, err := gitlab.TokenScopeParse(test.input) - assert.EqualValues(t, test.expected, val) - assert.EqualValues(t, test.expected.Value(), test.expected.String()) - if test.err { - assert.ErrorIs(t, err, gitlab.ErrUnknownTokenScope) - } else { - assert.NoError(t, err) - } - } -} diff --git a/with_admin_user_pat_gitlab_revokes_token_test.go b/with_admin_user_pat_gitlab_revokes_token_test.go index e38dc6c..1cd5dfe 100644 --- a/with_admin_user_pat_gitlab_revokes_token_test.go +++ b/with_admin_user_pat_gitlab_revokes_token_test.go @@ -60,7 +60,7 @@ func TestWithAdminUser_PAT_AdminUser_GitlabRevokesToken(t *testing.T) { "gitlab_revokes_token": strconv.FormatBool(true), "scopes": strings.Join( []string{ - gitlab.TokenScopeReadApi.String(), + token2.ScopeReadApi.String(), }, ","), }, diff --git a/with_admin_user_pat_vault_revokes_token_test.go b/with_admin_user_pat_vault_revokes_token_test.go index fab365a..4cc24e1 100644 --- a/with_admin_user_pat_vault_revokes_token_test.go +++ b/with_admin_user_pat_vault_revokes_token_test.go @@ -59,7 +59,7 @@ func TestWithAdminUser_PAT_AdminUser_VaultRevokesToken(t *testing.T) { "token_type": token2.TypePersonal.String(), "scopes": strings.Join( []string{ - gitlab.TokenScopeReadApi.String(), + token2.ScopeReadApi.String(), }, ","), "ttl": time.Hour, diff --git a/with_group_deploy_token_test.go b/with_group_deploy_token_test.go index 11f8332..1deff0b 100644 --- a/with_group_deploy_token_test.go +++ b/with_group_deploy_token_test.go @@ -56,7 +56,7 @@ func TestWithGroupDeployToken(t *testing.T) { "token_type": token2.TypeGroupDeploy.String(), "gitlab_revokes_token": strconv.FormatBool(false), "ttl": 120 * time.Hour, - "scopes": []string{gitlab.TokenScopeReadRepository.String()}, + "scopes": []string{token2.ScopeReadRepository.String()}, }, }) require.NoError(t, err) diff --git a/with_normal_user_gat_test.go b/with_normal_user_gat_test.go index e14b70b..355cf9b 100644 --- a/with_normal_user_gat_test.go +++ b/with_normal_user_gat_test.go @@ -58,7 +58,7 @@ func TestWithNormalUser_GAT(t *testing.T) { "ttl": time.Hour * 120, "gitlab_revokes_token": strconv.FormatBool(false), "access_level": gitlab.AccessLevelMaintainerPermissions.String(), - "scopes": strings.Join([]string{gitlab.TokenScopeReadApi.String()}, ","), + "scopes": strings.Join([]string{token2.ScopeReadApi.String()}, ","), }, }) require.NoError(t, err) diff --git a/with_normal_user_personal_at_fails_test.go b/with_normal_user_personal_at_fails_test.go index 5551e9d..cfbd1d8 100644 --- a/with_normal_user_personal_at_fails_test.go +++ b/with_normal_user_personal_at_fails_test.go @@ -54,7 +54,7 @@ func TestWithNormalUser_PersonalAT_Fails(t *testing.T) { "gitlab_revokes_token": strconv.FormatBool(true), "scopes": strings.Join( []string{ - gitlab.TokenScopeReadApi.String(), + token.ScopeReadApi.String(), }, ","), }, diff --git a/with_normal_user_project_at_test.go b/with_normal_user_project_at_test.go index 8a9bc22..2d1ffd1 100644 --- a/with_normal_user_project_at_test.go +++ b/with_normal_user_project_at_test.go @@ -61,7 +61,7 @@ func TestWithNormalUser_ProjectAT(t *testing.T) { "access_level": gitlab.AccessLevelMaintainerPermissions.String(), "scopes": strings.Join( []string{ - gitlab.TokenScopeReadApi.String(), + tok.ScopeReadApi.String(), }, ","), }, diff --git a/with_project_deploy_token_test.go b/with_project_deploy_token_test.go index d3db2c4..a9d79fa 100644 --- a/with_project_deploy_token_test.go +++ b/with_project_deploy_token_test.go @@ -56,7 +56,7 @@ func TestWithProjectDeployToken(t *testing.T) { "token_type": token2.TypeProjectDeploy.String(), "gitlab_revokes_token": strconv.FormatBool(false), "ttl": 120 * time.Hour, - "scopes": []string{gitlab.TokenScopeReadRepository.String()}, + "scopes": []string{token2.ScopeReadRepository.String()}, }, }) require.NoError(t, err) diff --git a/with_service_account_fail_test.go b/with_service_account_fail_test.go index 039c001..37246b0 100644 --- a/with_service_account_fail_test.go +++ b/with_service_account_fail_test.go @@ -60,7 +60,7 @@ func TestWithServiceAccountUserFail(t *testing.T) { "name": fmt.Sprintf(`user-service-account-%s`, usr.Username), "token_type": token.TypeUserServiceAccount.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, - "scopes": gitlab.ValidUserServiceAccountTokenScopes, + "scopes": token.ValidUserServiceAccountTokenScopes, "gitlab_revokes_token": false, }, }) diff --git a/with_service_account_group_test.go b/with_service_account_group_test.go index be9e78a..c50059a 100644 --- a/with_service_account_group_test.go +++ b/with_service_account_group_test.go @@ -65,7 +65,7 @@ func TestWithServiceAccountGroup(t *testing.T) { "name": `vault-generated-{{ .token_type }}-token`, "token_type": token2.TypeGroupServiceAccount.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, - "scopes": gitlab.ValidGroupServiceAccountTokenScopes, + "scopes": token2.ValidGroupServiceAccountTokenScopes, "gitlab_revokes_token": false, }, }) diff --git a/with_service_account_user_test.go b/with_service_account_user_test.go index 769659f..d066b24 100644 --- a/with_service_account_user_test.go +++ b/with_service_account_user_test.go @@ -63,7 +63,7 @@ func TestWithServiceAccountUser(t *testing.T) { "name": `vault-generated-{{ .token_type }}-token`, "token_type": token2.TypeUserServiceAccount.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, - "scopes": gitlab.ValidUserServiceAccountTokenScopes, + "scopes": token2.ValidUserServiceAccountTokenScopes, "gitlab_revokes_token": false, }, }) From 125fecd971b3cee7fec09de5805a1e3cf1bc5972 Mon Sep 17 00:00:00 2001 From: Ilija Matoski Date: Mon, 16 Jun 2025 20:53:39 +0200 Subject: [PATCH 09/17] rename functions to make more sense --- internal/token/scope.go | 2 +- internal/token/scope_test.go | 2 +- internal/token/type.go | 2 +- internal/token/type_test.go | 2 +- path_role.go | 2 +- secret_access_tokens.go | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/token/scope.go b/internal/token/scope.go index f59d883..01154cd 100644 --- a/internal/token/scope.go +++ b/internal/token/scope.go @@ -145,7 +145,7 @@ func (i Scope) Value() string { return i.String() } -func ScopeParse(value string) (Scope, error) { +func ParseScope(value string) (Scope, error) { if slices.Contains(ValidGroupTokenScopes, value) || slices.Contains(ValidPipelineProjectTokenScopes, value) || slices.Contains(ValidGroupDeployTokenScopes, value) || diff --git a/internal/token/scope_test.go b/internal/token/scope_test.go index 3385858..c9a0840 100644 --- a/internal/token/scope_test.go +++ b/internal/token/scope_test.go @@ -79,7 +79,7 @@ func TestTokenScope(t *testing.T) { for _, test := range tests { t.Logf("assert parse(%s) = %s (err: %v)", test.input, test.expected, test.err) - val, err := token.ScopeParse(test.input) + val, err := token.ParseScope(test.input) assert.EqualValues(t, test.expected, val) assert.EqualValues(t, test.expected.Value(), test.expected.String()) if test.err { diff --git a/internal/token/type.go b/internal/token/type.go index 6e37ef6..e577a95 100644 --- a/internal/token/type.go +++ b/internal/token/type.go @@ -43,7 +43,7 @@ func (i Type) Value() string { return i.String() } -func TypeParse(value string) (Type, error) { +func ParseType(value string) (Type, error) { if slices.Contains(ValidTokenTypes, value) { return Type(value), nil } diff --git a/internal/token/type_test.go b/internal/token/type_test.go index 526ed58..86b0057 100644 --- a/internal/token/type_test.go +++ b/internal/token/type_test.go @@ -63,7 +63,7 @@ func TestTokenType(t *testing.T) { for _, test := range tests { t.Logf("assert parse(%s) = %s (err: %v)", test.input, test.expected, test.err) - val, err := token.TypeParse(test.input) + val, err := token.ParseType(test.input) assert.EqualValues(t, test.expected, val) assert.EqualValues(t, test.expected.Value(), test.expected.String()) if test.err { diff --git a/path_role.go b/path_role.go index 2d35c29..1a37e85 100644 --- a/path_role.go +++ b/path_role.go @@ -220,7 +220,7 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data return logical.ErrorResponse(errs.ErrBackendNotConfigured.Error()), nil } - tokenType, _ = token.TypeParse(data.Get("token_type").(string)) + tokenType, _ = token.ParseType(data.Get("token_type").(string)) accessLevel, _ = AccessLevelParse(data.Get("access_level").(string)) var role = EntryRole{ diff --git a/secret_access_tokens.go b/secret_access_tokens.go index d727bad..633978f 100644 --- a/secret_access_tokens.go +++ b/secret_access_tokens.go @@ -84,7 +84,7 @@ func (b *Backend) secretAccessTokenRevoke(ctx context.Context, req *logical.Requ var parentId = req.Secret.InternalData["parent_id"].(string) var tokenType token.Type var tokenTypeValue = req.Secret.InternalData["token_type"].(string) - tokenType, _ = token.TypeParse(tokenTypeValue) + tokenType, _ = token.ParseType(tokenTypeValue) if vaultRevokesToken { var client Client From a2aa345b983a37afff2be4cb10fcbff5eb4d8f65 Mon Sep 17 00:00:00 2001 From: Ilija Matoski Date: Mon, 16 Jun 2025 20:58:52 +0200 Subject: [PATCH 10/17] move access level to token package --- entry_role.go | 18 +++++++-------- gitlab_client.go | 8 +++---- gitlab_client_test.go | 8 +++---- helpers_test.go | 4 ++-- internal/errs/errs.go | 8 +++++++ .../token/access_level.go | 2 +- .../token/access_level_test.go | 4 ++-- name_tpl_rand_string_test.go | 2 +- name_tpl_test.go | 8 +++---- name_tpl_unix_timestamp_test.go | 2 +- path_role.go | 22 +++++++++---------- path_role_deploy_tokens_test.go | 6 ++--- ...ole_pipeline_project_trigger_token_test.go | 6 ++--- path_role_test.go | 14 ++++++------ path_token_role_multiple_config_test.go | 6 ++--- path_token_role_test.go | 14 ++++++------ token_with_scopes_and_access_level.go | 6 +++-- with_normal_user_gat_test.go | 2 +- with_normal_user_project_at_test.go | 2 +- 19 files changed, 76 insertions(+), 66 deletions(-) rename type_access_level.go => internal/token/access_level.go (99%) rename type_access_level_test.go => internal/token/access_level_test.go (94%) diff --git a/entry_role.go b/entry_role.go index b97f2f1..0ef70d9 100644 --- a/entry_role.go +++ b/entry_role.go @@ -11,15 +11,15 @@ import ( ) type EntryRole struct { - RoleName string `json:"role_name" structs:"role_name" mapstructure:"role_name"` - TTL time.Duration `json:"ttl" structs:"ttl" mapstructure:"ttl"` - Path string `json:"path" structs:"path" mapstructure:"path"` - Name string `json:"name" structs:"name" mapstructure:"name"` - Scopes []string `json:"scopes" structs:"scopes" mapstructure:"scopes"` - AccessLevel AccessLevel `json:"access_level" structs:"access_level" mapstructure:"access_level,omitempty"` - TokenType token.Type `json:"token_type" structs:"token_type" mapstructure:"token_type"` - GitlabRevokesTokens bool `json:"gitlab_revokes_token" structs:"gitlab_revokes_token" mapstructure:"gitlab_revokes_token"` - ConfigName string `json:"config_name" structs:"config_name" mapstructure:"config_name"` + RoleName string `json:"role_name" structs:"role_name" mapstructure:"role_name"` + TTL time.Duration `json:"ttl" structs:"ttl" mapstructure:"ttl"` + Path string `json:"path" structs:"path" mapstructure:"path"` + Name string `json:"name" structs:"name" mapstructure:"name"` + Scopes []string `json:"scopes" structs:"scopes" mapstructure:"scopes"` + AccessLevel token.AccessLevel `json:"access_level" structs:"access_level" mapstructure:"access_level,omitempty"` + TokenType token.Type `json:"token_type" structs:"token_type" mapstructure:"token_type"` + GitlabRevokesTokens bool `json:"gitlab_revokes_token" structs:"gitlab_revokes_token" mapstructure:"gitlab_revokes_token"` + ConfigName string `json:"config_name" structs:"config_name" mapstructure:"config_name"` } func (e EntryRole) LogicalResponseData() map[string]any { diff --git a/gitlab_client.go b/gitlab_client.go index b1428da..e97b91d 100644 --- a/gitlab_client.go +++ b/gitlab_client.go @@ -32,8 +32,8 @@ type Client interface { CurrentTokenInfo(ctx context.Context) (*TokenConfig, error) RotateCurrentToken(ctx context.Context) (newToken *TokenConfig, oldToken *TokenConfig, err error) CreatePersonalAccessToken(ctx context.Context, username string, userId int, name string, expiresAt time.Time, scopes []string) (*TokenPersonal, error) - CreateGroupAccessToken(ctx context.Context, groupId string, name string, expiresAt time.Time, scopes []string, accessLevel AccessLevel) (*TokenGroup, error) - CreateProjectAccessToken(ctx context.Context, projectId string, name string, expiresAt time.Time, scopes []string, accessLevel AccessLevel) (*TokenProject, error) + CreateGroupAccessToken(ctx context.Context, groupId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (*TokenGroup, error) + CreateProjectAccessToken(ctx context.Context, projectId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (*TokenProject, error) RevokePersonalAccessToken(ctx context.Context, tokenId int) error RevokeProjectAccessToken(ctx context.Context, tokenId int, projectId string) error RevokeGroupAccessToken(ctx context.Context, tokenId int, groupId string) error @@ -460,7 +460,7 @@ func (gc *gitlabClient) CreatePersonalAccessToken(ctx context.Context, username return et, err } -func (gc *gitlabClient) CreateGroupAccessToken(ctx context.Context, groupId string, name string, expiresAt time.Time, scopes []string, accessLevel AccessLevel) (et *TokenGroup, err error) { +func (gc *gitlabClient) CreateGroupAccessToken(ctx context.Context, groupId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (et *TokenGroup, err error) { var at *g.GroupAccessToken defer func() { gc.logger.Debug("Create group access token", "gat", at, "et", et, "groupId", groupId, "name", name, "expiresAt", expiresAt, "scopes", scopes, "accessLevel", accessLevel, "error", err) @@ -493,7 +493,7 @@ func (gc *gitlabClient) CreateGroupAccessToken(ctx context.Context, groupId stri return et, err } -func (gc *gitlabClient) CreateProjectAccessToken(ctx context.Context, projectId string, name string, expiresAt time.Time, scopes []string, accessLevel AccessLevel) (et *TokenProject, err error) { +func (gc *gitlabClient) CreateProjectAccessToken(ctx context.Context, projectId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (et *TokenProject, err error) { var at *g.ProjectAccessToken defer func() { gc.logger.Debug("Create project access token", "gat", at, "et", et, "projectId", projectId, "name", name, "expiresAt", expiresAt, "scopes", scopes, "accessLevel", accessLevel, "error", err) diff --git a/gitlab_client_test.go b/gitlab_client_test.go index 1a9801d..365d64a 100644 --- a/gitlab_client_test.go +++ b/gitlab_client_test.go @@ -89,11 +89,11 @@ func TestGitlabClient_InvalidToken(t *testing.T) { _, err = client.GetUserIdByUsername(ctx, "username") require.Error(t, err) - gatToken, err := client.CreateGroupAccessToken(ctx, "groupId", "name", timeExpiresAt, []string{"scope"}, gitlab.AccessLevelUnknown) + gatToken, err := client.CreateGroupAccessToken(ctx, "groupId", "name", timeExpiresAt, []string{"scope"}, token2.AccessLevelUnknown) require.Error(t, err) require.Nil(t, gatToken) - prjAtToken, err := client.CreateProjectAccessToken(ctx, "projectId", "name", timeExpiresAt, []string{"scope"}, gitlab.AccessLevelUnknown) + prjAtToken, err := client.CreateProjectAccessToken(ctx, "projectId", "name", timeExpiresAt, []string{"scope"}, token2.AccessLevelUnknown) require.Error(t, err) require.Nil(t, prjAtToken) @@ -258,7 +258,7 @@ func TestGitlabClient_CreateAccessToken_And_Revoke(t *testing.T) { "name", timeExpiresAt, []string{token2.ScopeReadApi.String()}, - gitlab.AccessLevelGuestPermissions, + token2.AccessLevelGuestPermissions, ) require.NoError(t, err) require.NotNil(t, gatToken) @@ -272,7 +272,7 @@ func TestGitlabClient_CreateAccessToken_And_Revoke(t *testing.T) { "name", timeExpiresAt, []string{token2.ScopeReadApi.String()}, - gitlab.AccessLevelDeveloperPermissions, + token2.AccessLevelDeveloperPermissions, ) require.NoError(t, err) require.NotNil(t, prjatToken) diff --git a/helpers_test.go b/helpers_test.go index 46e4736..aae0c80 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -467,7 +467,7 @@ func (i *inMemoryClient) CreatePersonalAccessToken(ctx context.Context, username return entryToken, nil } -func (i *inMemoryClient) CreateGroupAccessToken(ctx context.Context, groupId string, name string, expiresAt time.Time, scopes []string, accessLevel gitlab.AccessLevel) (*gitlab.TokenGroup, error) { +func (i *inMemoryClient) CreateGroupAccessToken(ctx context.Context, groupId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (*gitlab.TokenGroup, error) { i.muLock.Lock() defer i.muLock.Unlock() if i.groupAccessTokenCreateError { @@ -495,7 +495,7 @@ func (i *inMemoryClient) CreateGroupAccessToken(ctx context.Context, groupId str return entryToken, nil } -func (i *inMemoryClient) CreateProjectAccessToken(ctx context.Context, projectId string, name string, expiresAt time.Time, scopes []string, accessLevel gitlab.AccessLevel) (*gitlab.TokenProject, error) { +func (i *inMemoryClient) CreateProjectAccessToken(ctx context.Context, projectId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (*gitlab.TokenProject, error) { i.muLock.Lock() defer i.muLock.Unlock() if i.projectAccessTokenCreateError { diff --git a/internal/errs/errs.go b/internal/errs/errs.go index 6d5084d..4fe01ba 100644 --- a/internal/errs/errs.go +++ b/internal/errs/errs.go @@ -18,7 +18,15 @@ var ( // ErrBackendNotConfigured represents an error when trying to use a backend that hasn't been properly configured ErrBackendNotConfigured = errors.New("backend not configured") + // ErrUnknown represents an error indicating an unknown or unspecified condition occurred. + ErrUnknown = errors.New("unknown") + + // ErrUnknownTokenType indicates an error when an undefined or unrecognized token type is encountered. ErrUnknownTokenType = errors.New("unknown token type") + // ErrUnknownTokenScope is returned when an unrecognized or undefined token scope is encountered. ErrUnknownTokenScope = errors.New("unknown token scope") + + // ErrUnknownAccessLevel indicates an error caused by encountering an undefined or unrecognized access level. + ErrUnknownAccessLevel = errors.New("unknown access level") ) diff --git a/type_access_level.go b/internal/token/access_level.go similarity index 99% rename from type_access_level.go rename to internal/token/access_level.go index 53e1d18..ac5527a 100644 --- a/type_access_level.go +++ b/internal/token/access_level.go @@ -1,4 +1,4 @@ -package gitlab +package token import ( "errors" diff --git a/type_access_level_test.go b/internal/token/access_level_test.go similarity index 94% rename from type_access_level_test.go rename to internal/token/access_level_test.go index d5cab4c..f6f4f57 100644 --- a/type_access_level_test.go +++ b/internal/token/access_level_test.go @@ -1,13 +1,13 @@ //go:build unit -package gitlab_test +package token_test import ( "testing" "github.com/stretchr/testify/assert" - gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) func TestAccessLevel(t *testing.T) { diff --git a/name_tpl_rand_string_test.go b/name_tpl_rand_string_test.go index 03922d3..45e74c9 100644 --- a/name_tpl_rand_string_test.go +++ b/name_tpl_rand_string_test.go @@ -20,7 +20,7 @@ func TestTokenNameGenerator_RandString(t *testing.T) { Path: "/path", Name: "{{ randHexString 8 }}", Scopes: []string{token.ScopeApi.String()}, - AccessLevel: g.AccessLevelNoPermissions, + AccessLevel: token.AccessLevelNoPermissions, TokenType: token.TypePersonal, GitlabRevokesTokens: false, }, diff --git a/name_tpl_test.go b/name_tpl_test.go index 32ae505..34b9298 100644 --- a/name_tpl_test.go +++ b/name_tpl_test.go @@ -29,7 +29,7 @@ func TestTokenNameGenerator(t *testing.T) { Path: "/path", Name: "{{ .role_name", Scopes: []string{token.ScopeApi.String()}, - AccessLevel: g.AccessLevelNoPermissions, + AccessLevel: token.AccessLevelNoPermissions, TokenType: token.TypePersonal, GitlabRevokesTokens: true, }, @@ -45,7 +45,7 @@ func TestTokenNameGenerator(t *testing.T) { Path: "/path", Name: "{{ .role_name }}-{{ .token_type }}-access-token-{{ yesNoBool .gitlab_revokes_token }}", Scopes: []string{token.ScopeApi.String()}, - AccessLevel: g.AccessLevelNoPermissions, + AccessLevel: token.AccessLevelNoPermissions, TokenType: token.TypePersonal, GitlabRevokesTokens: true, }, @@ -61,7 +61,7 @@ func TestTokenNameGenerator(t *testing.T) { Path: "/path", Name: "{{ .role_name }}-{{ .token_type }}-{{ stringsJoin .scopes \"-\" }}-{{ yesNoBool .gitlab_revokes_token }}", Scopes: []string{token.ScopeApi.String(), token.ScopeSudo.String()}, - AccessLevel: g.AccessLevelNoPermissions, + AccessLevel: token.AccessLevelNoPermissions, TokenType: token.TypePersonal, GitlabRevokesTokens: false, }, @@ -77,7 +77,7 @@ func TestTokenNameGenerator(t *testing.T) { Path: "/path", Name: "{{ .role_name }}-{{ .token_type }}-{{ timeNowFormat \"2006-01\" }}", Scopes: []string{token.ScopeApi.String(), token.ScopeSudo.String()}, - AccessLevel: g.AccessLevelNoPermissions, + AccessLevel: token.AccessLevelNoPermissions, TokenType: token.TypePersonal, GitlabRevokesTokens: false, }, diff --git a/name_tpl_unix_timestamp_test.go b/name_tpl_unix_timestamp_test.go index 3085f3b..12715c9 100644 --- a/name_tpl_unix_timestamp_test.go +++ b/name_tpl_unix_timestamp_test.go @@ -22,7 +22,7 @@ func TestTokenNameGenerator_UnixTimeStamp(t *testing.T) { Path: "/path", Name: "{{ .unix_timestamp_utc }}", Scopes: []string{token.ScopeApi.String()}, - AccessLevel: g.AccessLevelNoPermissions, + AccessLevel: token.AccessLevelNoPermissions, TokenType: token.TypePersonal, GitlabRevokesTokens: false, }, diff --git a/path_role.go b/path_role.go index 1a37e85..96b657b 100644 --- a/path_role.go +++ b/path_role.go @@ -77,7 +77,7 @@ var ( DisplayAttrs: &framework.DisplayAttributes{ Name: "Access Level", }, - AllowedValues: utils.ToAny(ValidAccessLevels...), + AllowedValues: utils.ToAny(token.ValidAccessLevels...), }, "token_type": { Type: framework.TypeString, @@ -206,7 +206,7 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data var err error var warnings []string var tokenType token.Type - var accessLevel AccessLevel + var accessLevel token.AccessLevel var configName = cmp.Or(data.Get("config_name").(string), TypeConfigDefault) b.lockClientMutex.RLock() @@ -221,7 +221,7 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data } tokenType, _ = token.ParseType(data.Get("token_type").(string)) - accessLevel, _ = AccessLevelParse(data.Get("access_level").(string)) + accessLevel, _ = token.AccessLevelParse(data.Get("access_level").(string)) var role = EntryRole{ RoleName: roleName, @@ -253,42 +253,42 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data switch tokenType { case token.TypePersonal: - validAccessLevels = ValidPersonalAccessLevels + validAccessLevels = token.ValidPersonalAccessLevels validScopes = token.ValidPersonalTokenScopes noEmptyScopes = false skipFields = []string{"config_name", "access_level"} case token.TypeGroup: - validAccessLevels = ValidGroupAccessLevels + validAccessLevels = token.ValidGroupAccessLevels validScopes = token.ValidGroupTokenScopes noEmptyScopes = false skipFields = []string{"config_name"} case token.TypeProject: - validAccessLevels = ValidProjectAccessLevels + validAccessLevels = token.ValidProjectAccessLevels validScopes = token.ValidProjectTokenScopes noEmptyScopes = false skipFields = []string{"config_name"} case token.TypeUserServiceAccount: - validAccessLevels = ValidUserServiceAccountAccessLevels + validAccessLevels = token.ValidUserServiceAccountAccessLevels validScopes = token.ValidUserServiceAccountTokenScopes noEmptyScopes = false skipFields = []string{"config_name", "access_level"} case token.TypeGroupServiceAccount: - validAccessLevels = ValidGroupServiceAccountAccessLevels + validAccessLevels = token.ValidGroupServiceAccountAccessLevels validScopes = token.ValidGroupServiceAccountTokenScopes noEmptyScopes = false skipFields = []string{"config_name", "access_level"} case token.TypePipelineProjectTrigger: - validAccessLevels = ValidPipelineProjectTriggerAccessLevels + validAccessLevels = token.ValidPipelineProjectTriggerAccessLevels validScopes = []string{} noEmptyScopes = false skipFields = []string{"config_name", "access_level", "scopes"} case token.TypeProjectDeploy: - validAccessLevels = ValidProjectDeployAccessLevels + validAccessLevels = token.ValidProjectDeployAccessLevels validScopes = token.ValidProjectDeployTokenScopes noEmptyScopes = true skipFields = []string{"config_name", "access_level"} case token.TypeGroupDeploy: - validAccessLevels = ValidGroupDeployAccessLevels + validAccessLevels = token.ValidGroupDeployAccessLevels validScopes = token.ValidGroupDeployTokenScopes noEmptyScopes = true skipFields = []string{"config_name", "access_level"} diff --git a/path_role_deploy_tokens_test.go b/path_role_deploy_tokens_test.go index a2175d6..e7bd85c 100644 --- a/path_role_deploy_tokens_test.go +++ b/path_role_deploy_tokens_test.go @@ -29,7 +29,7 @@ func TestPathRolesDeployTokens(t *testing.T) { var tests = []struct { tokenType token.Type - accessLevel gitlab.AccessLevel + accessLevel token.AccessLevel scopes []string ttl string path string @@ -59,7 +59,7 @@ func TestPathRolesDeployTokens(t *testing.T) { Data: map[string]any{ "path": tt.path, "name": tt.name, - "access_level": cmp.Or(tt.accessLevel, gitlab.AccessLevelUnknown).String(), + "access_level": cmp.Or(tt.accessLevel, token.AccessLevelUnknown).String(), "token_type": tt.tokenType.String(), "scopes": tt.scopes, "ttl": cmp.Or(tt.ttl, "1h"), @@ -79,7 +79,7 @@ func TestPathRolesDeployTokens(t *testing.T) { Data: map[string]any{ "path": tt.path, "name": tt.name, - "access_level": gitlab.AccessLevelNoPermissions.String(), + "access_level": token.AccessLevelNoPermissions.String(), "token_type": tt.tokenType.String(), "ttl": cmp.Or(tt.ttl, "1h"), "scopes": []string{}, diff --git a/path_role_pipeline_project_trigger_token_test.go b/path_role_pipeline_project_trigger_token_test.go index c0459e0..5b05ec4 100644 --- a/path_role_pipeline_project_trigger_token_test.go +++ b/path_role_pipeline_project_trigger_token_test.go @@ -37,7 +37,7 @@ func TestPathRolesPipelineProjectTrigger(t *testing.T) { Data: map[string]any{ "path": "user", "name": "Example user personal token", - "access_level": gitlab.AccessLevelNoPermissions.String(), + "access_level": token.AccessLevelNoPermissions.String(), "token_type": token.TypePipelineProjectTrigger.String(), "scopes": []string{token.ScopeApi.String()}, "ttl": "1h", @@ -59,7 +59,7 @@ func TestPathRolesPipelineProjectTrigger(t *testing.T) { Data: map[string]any{ "path": "user", "name": "Example user personal token", - "access_level": gitlab.AccessLevelUnknown.String(), + "access_level": token.AccessLevelUnknown.String(), "token_type": token.TypePipelineProjectTrigger.String(), "scopes": []string{}, "ttl": "1h", @@ -80,7 +80,7 @@ func TestPathRolesPipelineProjectTrigger(t *testing.T) { Data: map[string]any{ "path": "user", "name": "Example user personal token", - "access_level": gitlab.AccessLevelUnknown.String(), + "access_level": token.AccessLevelUnknown.String(), "token_type": token.TypePipelineProjectTrigger.String(), "scopes": []string{}, }, diff --git a/path_role_test.go b/path_role_test.go index 3208f36..269ea8d 100644 --- a/path_role_test.go +++ b/path_role_test.go @@ -102,7 +102,7 @@ func TestPathRoles(t *testing.T) { Data: map[string]any{ "path": "user", "name": token.TypePersonal.String(), - "access_level": gitlab.AccessLevelOwnerPermissions.String(), + "access_level": token.AccessLevelOwnerPermissions.String(), "token_type": token.TypePersonal.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": token.ValidPersonalTokenScopes, @@ -146,7 +146,7 @@ func TestPathRoles(t *testing.T) { Data: map[string]any{ "path": "user", "name": token.TypeProject.String(), - "access_level": gitlab.AccessLevelOwnerPermissions.String(), + "access_level": token.AccessLevelOwnerPermissions.String(), "token_type": token.TypeProject.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": token.ValidProjectTokenScopes, @@ -191,7 +191,7 @@ func TestPathRoles(t *testing.T) { Data: map[string]any{ "path": "user", "name": token.TypeGroup.String(), - "access_level": gitlab.AccessLevelOwnerPermissions.String(), + "access_level": token.AccessLevelOwnerPermissions.String(), "token_type": token.TypeGroup.String(), "ttl": gitlab.DefaultAccessTokenMinTTL, "scopes": token.ValidGroupTokenScopes, @@ -258,7 +258,7 @@ func TestPathRoles(t *testing.T) { Data: map[string]any{ "path": "user", "name": "Example user personal token", - "access_level": gitlab.AccessLevelOwnerPermissions.String(), + "access_level": token.AccessLevelOwnerPermissions.String(), "ttl": "48h", "token_type": token.TypeProject.String(), "scopes": token.ValidProjectTokenScopes, @@ -279,7 +279,7 @@ func TestPathRoles(t *testing.T) { Data: map[string]any{ "path": "user", "name": "Example project personal token", - "access_level": gitlab.AccessLevelOwnerPermissions.String(), + "access_level": token.AccessLevelOwnerPermissions.String(), "token_type": token.TypeProject.String(), "ttl": "48h", "scopes": token.ValidPersonalTokenScopes, @@ -349,7 +349,7 @@ func TestPathRoles(t *testing.T) { "path": "user", "name": "Example user personal token", "ttl": "48h", - "access_level": gitlab.AccessLevelOwnerPermissions.String(), + "access_level": token.AccessLevelOwnerPermissions.String(), "token_type": token.TypeGroup.String(), "scopes": token.ValidProjectTokenScopes, }, @@ -369,7 +369,7 @@ func TestPathRoles(t *testing.T) { Data: map[string]any{ "path": "user", "name": "Example user personal token", - "access_level": gitlab.AccessLevelOwnerPermissions.String(), + "access_level": token.AccessLevelOwnerPermissions.String(), "token_type": token.TypeGroup.String(), "scopes": token.ValidPersonalTokenScopes, }, diff --git a/path_token_role_multiple_config_test.go b/path_token_role_multiple_config_test.go index 1b5c1d4..d775021 100644 --- a/path_token_role_multiple_config_test.go +++ b/path_token_role_multiple_config_test.go @@ -47,7 +47,7 @@ func TestPathTokenRolesMultipleConfigs(t *testing.T) { type roleData struct { roleName, path, tokenName string tokenType token.Type - accessLevel gitlab.AccessLevel + accessLevel token.AccessLevel scopes []string } var roles = map[string][]roleData{ @@ -72,7 +72,7 @@ func TestPathTokenRolesMultipleConfigs(t *testing.T) { roleName: "admin-example-example", path: "example/example", tokenType: token.TypeProject, - accessLevel: gitlab.AccessLevelGuestPermissions, + accessLevel: token.AccessLevelGuestPermissions, scopes: []string{token.ScopeApi.String(), token.ScopeSelfRotate.String()}, tokenName: "admin_user_initial_token", }, @@ -82,7 +82,7 @@ func TestPathTokenRolesMultipleConfigs(t *testing.T) { roleName: "normal-example", path: "example", tokenType: token.TypeGroup, - accessLevel: gitlab.AccessLevelGuestPermissions, + accessLevel: token.AccessLevelGuestPermissions, scopes: []string{token.ScopeApi.String(), token.ScopeSelfRotate.String()}, tokenName: "normal_user_initial_token", }, diff --git a/path_token_role_test.go b/path_token_role_test.go index 9bd28df..0f043e4 100644 --- a/path_token_role_test.go +++ b/path_token_role_test.go @@ -37,7 +37,7 @@ func TestPathTokenRoles(t *testing.T) { require.ErrorIs(t, err, gitlab.ErrRoleNotFound) }) - var generalTokenCreation = func(t *testing.T, tokenType token.Type, level gitlab.AccessLevel, gitlabRevokesToken bool) { + var generalTokenCreation = func(t *testing.T, tokenType token.Type, level token.AccessLevel, gitlabRevokesToken bool) { t.Logf("token creation, token type: %s, level: %s, gitlab revokes token: %t", tokenType, level, gitlabRevokesToken) ctx := getCtxGitlabClient(t, "unit") client := newInMemoryClient(true) @@ -152,17 +152,17 @@ func TestPathTokenRoles(t *testing.T) { } t.Run("personal access token", func(t *testing.T) { - generalTokenCreation(t, token.TypePersonal, gitlab.AccessLevelUnknown, false) - generalTokenCreation(t, token.TypePersonal, gitlab.AccessLevelUnknown, true) + generalTokenCreation(t, token.TypePersonal, token.AccessLevelUnknown, false) + generalTokenCreation(t, token.TypePersonal, token.AccessLevelUnknown, true) }) t.Run("project access token", func(t *testing.T) { - generalTokenCreation(t, token.TypeProject, gitlab.AccessLevelGuestPermissions, false) - generalTokenCreation(t, token.TypeProject, gitlab.AccessLevelGuestPermissions, true) + generalTokenCreation(t, token.TypeProject, token.AccessLevelGuestPermissions, false) + generalTokenCreation(t, token.TypeProject, token.AccessLevelGuestPermissions, true) }) t.Run("group access token", func(t *testing.T) { - generalTokenCreation(t, token.TypeGroup, gitlab.AccessLevelGuestPermissions, false) - generalTokenCreation(t, token.TypeGroup, gitlab.AccessLevelGuestPermissions, true) + generalTokenCreation(t, token.TypeGroup, token.AccessLevelGuestPermissions, false) + generalTokenCreation(t, token.TypeGroup, token.AccessLevelGuestPermissions, true) }) } diff --git a/token_with_scopes_and_access_level.go b/token_with_scopes_and_access_level.go index 6aacc72..7acabf8 100644 --- a/token_with_scopes_and_access_level.go +++ b/token_with_scopes_and_access_level.go @@ -3,13 +3,15 @@ package gitlab import ( "maps" "strings" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) type TokenWithScopesAndAccessLevel struct { Token `json:",inline"` - Scopes []string `json:"scopes"` - AccessLevel AccessLevel `json:"access_level"` + Scopes []string `json:"scopes"` + AccessLevel token.AccessLevel `json:"access_level"` } func (t *TokenWithScopesAndAccessLevel) Internal() (d map[string]any) { diff --git a/with_normal_user_gat_test.go b/with_normal_user_gat_test.go index 355cf9b..55e8d9f 100644 --- a/with_normal_user_gat_test.go +++ b/with_normal_user_gat_test.go @@ -57,7 +57,7 @@ func TestWithNormalUser_GAT(t *testing.T) { "token_type": token2.TypeGroup.String(), "ttl": time.Hour * 120, "gitlab_revokes_token": strconv.FormatBool(false), - "access_level": gitlab.AccessLevelMaintainerPermissions.String(), + "access_level": token2.AccessLevelMaintainerPermissions.String(), "scopes": strings.Join([]string{token2.ScopeReadApi.String()}, ","), }, }) diff --git a/with_normal_user_project_at_test.go b/with_normal_user_project_at_test.go index 2d1ffd1..ab89cce 100644 --- a/with_normal_user_project_at_test.go +++ b/with_normal_user_project_at_test.go @@ -58,7 +58,7 @@ func TestWithNormalUser_ProjectAT(t *testing.T) { "token_type": tok.TypeProject.String(), "ttl": time.Hour * 120, "gitlab_revokes_token": strconv.FormatBool(false), - "access_level": gitlab.AccessLevelMaintainerPermissions.String(), + "access_level": tok.AccessLevelMaintainerPermissions.String(), "scopes": strings.Join( []string{ tok.ScopeReadApi.String(), From 4017ad46f2348bd620673eb4f11f4b97642fdf1a Mon Sep 17 00:00:00 2001 From: Ilija Matoski Date: Sun, 22 Jun 2025 20:47:31 +0200 Subject: [PATCH 11/17] move models to internal/models --- gitlab_client.go | 101 +++++++++--------- helpers_test.go | 85 +++++++-------- token.go => internal/models/token.go | 77 ++++++++++--- internal/models/token_config.go | 34 ++++++ internal/models/token_config_test.go | 19 ++++ internal/models/token_group.go | 9 ++ .../models/token_group_deploy.go | 6 +- internal/models/token_group_deploy_test.go | 19 ++++ .../models/token_group_service_account.go | 6 +- .../token_group_service_account_test.go | 19 ++++ .../models/token_personal.go | 6 +- internal/models/token_personal_test.go | 19 ++++ .../models/token_pipeline_project_trigger.go | 9 ++ internal/models/token_project.go | 9 ++ .../models/token_project_deploy.go | 10 +- internal/models/token_project_deploy_test.go | 19 ++++ internal/models/token_test.go | 68 ++++++++++++ internal/models/token_user_service_account.go | 9 ++ internal/token/token.go | 19 ++++ path_config.go | 3 +- path_config_rotate.go | 3 +- path_token_role.go | 2 +- token_config.go | 7 -- token_group.go | 5 - token_pipeline_project_trigger.go | 5 - token_project.go | 5 - token_user_service_account.go | 5 - token_with_scopes.go | 32 ------ token_with_scopes_and_access_level.go | 44 -------- 29 files changed, 436 insertions(+), 218 deletions(-) rename token.go => internal/models/token.go (63%) create mode 100644 internal/models/token_config.go create mode 100644 internal/models/token_config_test.go create mode 100644 internal/models/token_group.go rename token_group_deploy.go => internal/models/token_group_deploy.go (82%) create mode 100644 internal/models/token_group_deploy_test.go rename token_group_service_account.go => internal/models/token_group_service_account.go (82%) create mode 100644 internal/models/token_group_service_account_test.go rename token_personal.go => internal/models/token_personal.go (82%) create mode 100644 internal/models/token_personal_test.go create mode 100644 internal/models/token_pipeline_project_trigger.go create mode 100644 internal/models/token_project.go rename token_project_deploy.go => internal/models/token_project_deploy.go (80%) create mode 100644 internal/models/token_project_deploy_test.go create mode 100644 internal/models/token_test.go create mode 100644 internal/models/token_user_service_account.go create mode 100644 internal/token/token.go delete mode 100644 token_config.go delete mode 100644 token_group.go delete mode 100644 token_pipeline_project_trigger.go delete mode 100644 token_project.go delete mode 100644 token_user_service_account.go delete mode 100644 token_with_scopes.go delete mode 100644 token_with_scopes_and_access_level.go diff --git a/gitlab_client.go b/gitlab_client.go index e97b91d..ab676fa 100644 --- a/gitlab_client.go +++ b/gitlab_client.go @@ -16,6 +16,7 @@ import ( "golang.org/x/time/rate" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/models" t "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) @@ -29,26 +30,26 @@ type Client interface { GitlabClient(ctx context.Context) *g.Client Valid(ctx context.Context) bool Metadata(ctx context.Context) (*g.Metadata, error) - CurrentTokenInfo(ctx context.Context) (*TokenConfig, error) - RotateCurrentToken(ctx context.Context) (newToken *TokenConfig, oldToken *TokenConfig, err error) - CreatePersonalAccessToken(ctx context.Context, username string, userId int, name string, expiresAt time.Time, scopes []string) (*TokenPersonal, error) - CreateGroupAccessToken(ctx context.Context, groupId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (*TokenGroup, error) - CreateProjectAccessToken(ctx context.Context, projectId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (*TokenProject, error) + CurrentTokenInfo(ctx context.Context) (*models.TokenConfig, error) + RotateCurrentToken(ctx context.Context) (newToken *models.TokenConfig, oldToken *models.TokenConfig, err error) + CreatePersonalAccessToken(ctx context.Context, username string, userId int, name string, expiresAt time.Time, scopes []string) (*models.TokenPersonal, error) + CreateGroupAccessToken(ctx context.Context, groupId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (*models.TokenGroup, error) + CreateProjectAccessToken(ctx context.Context, projectId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (*models.TokenProject, error) RevokePersonalAccessToken(ctx context.Context, tokenId int) error RevokeProjectAccessToken(ctx context.Context, tokenId int, projectId string) error RevokeGroupAccessToken(ctx context.Context, tokenId int, groupId string) error GetUserIdByUsername(ctx context.Context, username string) (int, error) GetGroupIdByPath(ctx context.Context, path string) (int, error) GetProjectIdByPath(ctx context.Context, path string) (int, error) - CreateGroupServiceAccountAccessToken(ctx context.Context, group string, groupId string, userId int, name string, expiresAt time.Time, scopes []string) (*TokenGroupServiceAccount, error) - CreateUserServiceAccountAccessToken(ctx context.Context, username string, userId int, name string, expiresAt time.Time, scopes []string) (*TokenUserServiceAccount, error) + CreateGroupServiceAccountAccessToken(ctx context.Context, group string, groupId string, userId int, name string, expiresAt time.Time, scopes []string) (*models.TokenGroupServiceAccount, error) + CreateUserServiceAccountAccessToken(ctx context.Context, username string, userId int, name string, expiresAt time.Time, scopes []string) (*models.TokenUserServiceAccount, error) RevokeUserServiceAccountAccessToken(ctx context.Context, token string) error RevokeGroupServiceAccountAccessToken(ctx context.Context, token string) error - CreatePipelineProjectTriggerAccessToken(ctx context.Context, path, name string, projectId int, description string, expiresAt *time.Time) (*TokenPipelineProjectTrigger, error) + CreatePipelineProjectTriggerAccessToken(ctx context.Context, path, name string, projectId int, description string, expiresAt *time.Time) (*models.TokenPipelineProjectTrigger, error) RevokePipelineProjectTriggerAccessToken(ctx context.Context, projectId int, tokenId int) error - CreateProjectDeployToken(ctx context.Context, path string, projectId int, name string, expiresAt *time.Time, scopes []string) (et *TokenProjectDeploy, err error) + CreateProjectDeployToken(ctx context.Context, path string, projectId int, name string, expiresAt *time.Time, scopes []string) (et *models.TokenProjectDeploy, err error) RevokeProjectDeployToken(ctx context.Context, projectId, deployTokenId int) (err error) - CreateGroupDeployToken(ctx context.Context, path string, groupId int, name string, expiresAt *time.Time, scopes []string) (et *TokenGroupDeploy, err error) + CreateGroupDeployToken(ctx context.Context, path string, groupId int, name string, expiresAt *time.Time, scopes []string) (et *models.TokenGroupDeploy, err error) RevokeGroupDeployToken(ctx context.Context, groupId, deployTokenId int) (err error) } @@ -73,7 +74,7 @@ func (gc *gitlabClient) GetProjectIdByPath(ctx context.Context, path string) (pr return projectId, err } -func (gc *gitlabClient) CreateGroupDeployToken(ctx context.Context, path string, groupId int, name string, expiresAt *time.Time, scopes []string) (et *TokenGroupDeploy, err error) { +func (gc *gitlabClient) CreateGroupDeployToken(ctx context.Context, path string, groupId int, name string, expiresAt *time.Time, scopes []string) (et *models.TokenGroupDeploy, err error) { var dt *g.DeployToken defer func() { gc.logger.Debug("Create group deploy token", "groupId", groupId, "name", name, "path", path, "expiresAt", expiresAt, "scopes", scopes, "error", err) @@ -88,9 +89,9 @@ func (gc *gitlabClient) CreateGroupDeployToken(ctx context.Context, path string, }, g.WithContext(ctx), ); err == nil { - et = &TokenGroupDeploy{ - TokenWithScopes: TokenWithScopes{ - Token: Token{ + et = &models.TokenGroupDeploy{ + TokenWithScopes: models.TokenWithScopes{ + Token: models.Token{ TokenID: dt.ID, ParentID: strconv.Itoa(groupId), Path: path, @@ -107,7 +108,7 @@ func (gc *gitlabClient) CreateGroupDeployToken(ctx context.Context, path string, return et, err } -func (gc *gitlabClient) CreateProjectDeployToken(ctx context.Context, path string, projectId int, name string, expiresAt *time.Time, scopes []string) (et *TokenProjectDeploy, err error) { +func (gc *gitlabClient) CreateProjectDeployToken(ctx context.Context, path string, projectId int, name string, expiresAt *time.Time, scopes []string) (et *models.TokenProjectDeploy, err error) { var dt *g.DeployToken defer func() { gc.logger.Debug("Create project deploy token", "projectId", projectId, "name", name, "path", path, "expiresAt", expiresAt, "scopes", scopes, "error", err) @@ -121,9 +122,9 @@ func (gc *gitlabClient) CreateProjectDeployToken(ctx context.Context, path strin }, g.WithContext(ctx), ); err == nil { - et = &TokenProjectDeploy{ - TokenWithScopes: TokenWithScopes{ - Token: Token{ + et = &models.TokenProjectDeploy{ + TokenWithScopes: models.TokenWithScopes{ + Token: models.Token{ TokenID: dt.ID, ParentID: strconv.Itoa(projectId), Path: path, @@ -167,7 +168,7 @@ func (gc *gitlabClient) Metadata(ctx context.Context) (metadata *g.Metadata, err return metadata, err } -func (gc *gitlabClient) CreatePipelineProjectTriggerAccessToken(ctx context.Context, path, name string, projectId int, description string, expiresAt *time.Time) (et *TokenPipelineProjectTrigger, err error) { +func (gc *gitlabClient) CreatePipelineProjectTriggerAccessToken(ctx context.Context, path, name string, projectId int, description string, expiresAt *time.Time) (et *models.TokenPipelineProjectTrigger, err error) { var pt *g.PipelineTrigger defer func() { gc.logger.Debug("Create a pipeline project trigger access token", "path", path, "name", name, "projectId", description, "description", "error", err) @@ -178,8 +179,8 @@ func (gc *gitlabClient) CreatePipelineProjectTriggerAccessToken(ctx context.Cont &g.AddPipelineTriggerOptions{Description: &description}, g.WithContext(ctx), ); err == nil { - et = &TokenPipelineProjectTrigger{ - Token: Token{ + et = &models.TokenPipelineProjectTrigger{ + Token: models.Token{ TokenID: pt.ID, ParentID: strconv.Itoa(projectId), Path: path, @@ -229,7 +230,7 @@ func (gc *gitlabClient) GitlabClient(ctx context.Context) *g.Client { return gc.client } -func (gc *gitlabClient) CreateGroupServiceAccountAccessToken(ctx context.Context, path string, groupId string, userId int, name string, expiresAt time.Time, scopes []string) (et *TokenGroupServiceAccount, err error) { +func (gc *gitlabClient) CreateGroupServiceAccountAccessToken(ctx context.Context, path string, groupId string, userId int, name string, expiresAt time.Time, scopes []string) (et *models.TokenGroupServiceAccount, err error) { var at *g.PersonalAccessToken defer func() { gc.logger.Debug("Create group service access token", "pat", at, "et", et, "path", path, "groupId", groupId, "userId", userId, "name", name, "expiresAt", expiresAt, "scopes", scopes, "error", err) @@ -240,9 +241,9 @@ func (gc *gitlabClient) CreateGroupServiceAccountAccessToken(ctx context.Context Scopes: &scopes, }, g.WithContext(ctx)) if err == nil { - et = &TokenGroupServiceAccount{ - TokenWithScopes: TokenWithScopes{ - Token: Token{ + et = &models.TokenGroupServiceAccount{ + TokenWithScopes: models.TokenWithScopes{ + Token: models.Token{ TokenID: at.ID, ParentID: groupId, Path: path, @@ -260,16 +261,16 @@ func (gc *gitlabClient) CreateGroupServiceAccountAccessToken(ctx context.Context return et, err } -func (gc *gitlabClient) CreateUserServiceAccountAccessToken(ctx context.Context, username string, userId int, name string, expiresAt time.Time, scopes []string) (et *TokenUserServiceAccount, err error) { +func (gc *gitlabClient) CreateUserServiceAccountAccessToken(ctx context.Context, username string, userId int, name string, expiresAt time.Time, scopes []string) (et *models.TokenUserServiceAccount, err error) { defer func() { gc.logger.Debug("Create user service access token", "et", et, "username", username, "userId", userId, "name", name, "expiresAt", expiresAt, "scopes", scopes, "error", err) }() - var etp *TokenPersonal + var etp *models.TokenPersonal etp, err = gc.CreatePersonalAccessToken(ctx, username, userId, name, expiresAt, scopes) if err == nil && etp != nil { - et = &TokenUserServiceAccount{ - TokenWithScopes: TokenWithScopes{ - Token: Token{ + et = &models.TokenUserServiceAccount{ + TokenWithScopes: models.TokenWithScopes{ + Token: models.Token{ TokenID: etp.TokenID, ParentID: etp.ParentID, Path: etp.Path, @@ -322,13 +323,13 @@ func (gc *gitlabClient) RevokeGroupServiceAccountAccessToken(ctx context.Context return err } -func (gc *gitlabClient) CurrentTokenInfo(ctx context.Context) (et *TokenConfig, err error) { +func (gc *gitlabClient) CurrentTokenInfo(ctx context.Context) (et *models.TokenConfig, err error) { var pat *g.PersonalAccessToken defer func() { gc.logger.Debug("Current token info", "token", et, "error", err) }() if pat, _, err = gc.client.PersonalAccessTokens.GetSinglePersonalAccessToken(g.WithContext(ctx)); err == nil { - et = &TokenConfig{ - TokenWithScopes: TokenWithScopes{ - Token: Token{ + et = &models.TokenConfig{ + TokenWithScopes: models.TokenWithScopes{ + Token: models.Token{ TokenID: pat.ID, Name: pat.Name, Token: pat.Token, @@ -351,7 +352,7 @@ func (gc *gitlabClient) CurrentTokenInfo(ctx context.Context) (et *TokenConfig, return et, err } -func (gc *gitlabClient) RotateCurrentToken(ctx context.Context) (token *TokenConfig, currentEntryToken *TokenConfig, err error) { +func (gc *gitlabClient) RotateCurrentToken(ctx context.Context) (token *models.TokenConfig, currentEntryToken *models.TokenConfig, err error) { var expiresAt time.Time defer func() { gc.logger.Debug("Rotate current token", "token", token, "currentEntryToken", currentEntryToken, "expiresAt", expiresAt, "error", err) @@ -380,9 +381,9 @@ func (gc *gitlabClient) RotateCurrentToken(ctx context.Context) (token *TokenCon return nil, nil, err } - token = &TokenConfig{ - TokenWithScopes: TokenWithScopes{ - Token: Token{ + token = &models.TokenConfig{ + TokenWithScopes: models.TokenWithScopes{ + Token: models.Token{ TokenID: pat.ID, ParentID: "", Path: usr.Username, @@ -431,7 +432,7 @@ func (gc *gitlabClient) GetUserIdByUsername(ctx context.Context, username string return userId, nil } -func (gc *gitlabClient) CreatePersonalAccessToken(ctx context.Context, username string, userId int, name string, expiresAt time.Time, scopes []string) (et *TokenPersonal, err error) { +func (gc *gitlabClient) CreatePersonalAccessToken(ctx context.Context, username string, userId int, name string, expiresAt time.Time, scopes []string) (et *models.TokenPersonal, err error) { var at *g.PersonalAccessToken defer func() { gc.logger.Debug("Create personal access token", "pat", at, "et", et, "username", username, "userId", userId, "name", name, "expiresAt", expiresAt, "scopes", scopes, "error", err) @@ -441,9 +442,9 @@ func (gc *gitlabClient) CreatePersonalAccessToken(ctx context.Context, username ExpiresAt: (*g.ISOTime)(&expiresAt), Scopes: &scopes, }, g.WithContext(ctx)); err == nil { - et = &TokenPersonal{ - TokenWithScopes: TokenWithScopes{ - Token: Token{ + et = &models.TokenPersonal{ + TokenWithScopes: models.TokenWithScopes{ + Token: models.Token{ TokenID: at.ID, Path: username, Name: name, @@ -460,7 +461,7 @@ func (gc *gitlabClient) CreatePersonalAccessToken(ctx context.Context, username return et, err } -func (gc *gitlabClient) CreateGroupAccessToken(ctx context.Context, groupId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (et *TokenGroup, err error) { +func (gc *gitlabClient) CreateGroupAccessToken(ctx context.Context, groupId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (et *models.TokenGroup, err error) { var at *g.GroupAccessToken defer func() { gc.logger.Debug("Create group access token", "gat", at, "et", et, "groupId", groupId, "name", name, "expiresAt", expiresAt, "scopes", scopes, "accessLevel", accessLevel, "error", err) @@ -473,9 +474,9 @@ func (gc *gitlabClient) CreateGroupAccessToken(ctx context.Context, groupId stri ExpiresAt: (*g.ISOTime)(&expiresAt), AccessLevel: al, }, g.WithContext(ctx)); err == nil { - et = &TokenGroup{ - TokenWithScopesAndAccessLevel: TokenWithScopesAndAccessLevel{ - Token: Token{ + et = &models.TokenGroup{ + TokenWithScopesAndAccessLevel: models.TokenWithScopesAndAccessLevel{ + Token: models.Token{ TokenID: at.ID, ParentID: groupId, Path: groupId, @@ -493,7 +494,7 @@ func (gc *gitlabClient) CreateGroupAccessToken(ctx context.Context, groupId stri return et, err } -func (gc *gitlabClient) CreateProjectAccessToken(ctx context.Context, projectId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (et *TokenProject, err error) { +func (gc *gitlabClient) CreateProjectAccessToken(ctx context.Context, projectId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (et *models.TokenProject, err error) { var at *g.ProjectAccessToken defer func() { gc.logger.Debug("Create project access token", "gat", at, "et", et, "projectId", projectId, "name", name, "expiresAt", expiresAt, "scopes", scopes, "accessLevel", accessLevel, "error", err) @@ -506,9 +507,9 @@ func (gc *gitlabClient) CreateProjectAccessToken(ctx context.Context, projectId ExpiresAt: (*g.ISOTime)(&expiresAt), AccessLevel: al, }, g.WithContext(ctx)); err == nil { - et = &TokenProject{ - TokenWithScopesAndAccessLevel: TokenWithScopesAndAccessLevel{ - Token: Token{ + et = &models.TokenProject{ + TokenWithScopesAndAccessLevel: models.TokenWithScopesAndAccessLevel{ + Token: models.Token{ TokenID: at.ID, ParentID: projectId, Path: projectId, diff --git a/helpers_test.go b/helpers_test.go index aae0c80..27c6224 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -28,6 +28,7 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/flags" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/models" t "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) @@ -153,19 +154,19 @@ func newInMemoryClient(valid bool) *inMemoryClient { return &inMemoryClient{ users: make([]string, 0), valid: valid, - accessTokens: make(map[string]gitlab.IToken), + accessTokens: make(map[string]t.Token), - mainTokenInfo: gitlab.TokenConfig{ - TokenWithScopes: gitlab.TokenWithScopes{ - Token: gitlab.Token{ + mainTokenInfo: models.TokenConfig{ + TokenWithScopes: models.TokenWithScopes{ + Token: models.Token{ CreatedAt: g.Ptr(time.Now()), ExpiresAt: g.Ptr(time.Now()), }, }, }, - rotateMainToken: gitlab.TokenConfig{ - TokenWithScopes: gitlab.TokenWithScopes{ - Token: gitlab.Token{ + rotateMainToken: models.TokenConfig{ + TokenWithScopes: models.TokenWithScopes{ + Token: models.Token{ CreatedAt: g.Ptr(time.Now()), ExpiresAt: g.Ptr(time.Now()), }, @@ -204,10 +205,10 @@ type inMemoryClient struct { calledRotateMainToken int calledValid int - mainTokenInfo gitlab.TokenConfig - rotateMainToken gitlab.TokenConfig + mainTokenInfo models.TokenConfig + rotateMainToken models.TokenConfig - accessTokens map[string]gitlab.IToken + accessTokens map[string]t.Token valueGetProjectIdByPath int } @@ -219,7 +220,7 @@ func (i *inMemoryClient) GetProjectIdByPath(ctx context.Context, path string) (i return i.valueGetProjectIdByPath, nil } -func (i *inMemoryClient) CreateProjectDeployToken(ctx context.Context, path string, projectId int, name string, expiresAt *time.Time, scopes []string) (et *gitlab.TokenProjectDeploy, err error) { +func (i *inMemoryClient) CreateProjectDeployToken(ctx context.Context, path string, projectId int, name string, expiresAt *time.Time, scopes []string) (et *models.TokenProjectDeploy, err error) { i.muLock.Lock() defer i.muLock.Unlock() if i.createProjectDeployTokenError { @@ -228,9 +229,9 @@ func (i *inMemoryClient) CreateProjectDeployToken(ctx context.Context, path stri i.internalCounter++ var tokenId = i.internalCounter key := fmt.Sprintf("%s_%v_%v", t.TypeProjectDeploy.String(), projectId, tokenId) - var entryToken = &gitlab.TokenProjectDeploy{ - TokenWithScopes: gitlab.TokenWithScopes{ - Token: gitlab.Token{ + var entryToken = &models.TokenProjectDeploy{ + TokenWithScopes: models.TokenWithScopes{ + Token: models.Token{ TokenID: tokenId, ParentID: strconv.Itoa(projectId), Path: path, @@ -247,7 +248,7 @@ func (i *inMemoryClient) CreateProjectDeployToken(ctx context.Context, path stri return entryToken, nil } -func (i *inMemoryClient) CreateGroupDeployToken(ctx context.Context, path string, groupId int, name string, expiresAt *time.Time, scopes []string) (et *gitlab.TokenGroupDeploy, err error) { +func (i *inMemoryClient) CreateGroupDeployToken(ctx context.Context, path string, groupId int, name string, expiresAt *time.Time, scopes []string) (et *models.TokenGroupDeploy, err error) { i.muLock.Lock() defer i.muLock.Unlock() if i.createGroupDeployTokenError { @@ -256,9 +257,9 @@ func (i *inMemoryClient) CreateGroupDeployToken(ctx context.Context, path string i.internalCounter++ var tokenId = i.internalCounter key := fmt.Sprintf("%s_%v_%v", t.TypeGroupDeploy.String(), groupId, tokenId) - var entryToken = &gitlab.TokenGroupDeploy{ - TokenWithScopes: gitlab.TokenWithScopes{ - Token: gitlab.Token{ + var entryToken = &models.TokenGroupDeploy{ + TokenWithScopes: models.TokenWithScopes{ + Token: models.Token{ TokenID: tokenId, ParentID: strconv.Itoa(groupId), Path: path, @@ -309,7 +310,7 @@ func (i *inMemoryClient) Metadata(ctx context.Context) (*g.Metadata, error) { }, nil } -func (i *inMemoryClient) CreatePipelineProjectTriggerAccessToken(ctx context.Context, path, name string, projectId int, description string, expiresAt *time.Time) (et *gitlab.TokenPipelineProjectTrigger, err error) { +func (i *inMemoryClient) CreatePipelineProjectTriggerAccessToken(ctx context.Context, path, name string, projectId int, description string, expiresAt *time.Time) (et *models.TokenPipelineProjectTrigger, err error) { i.muLock.Lock() defer i.muLock.Unlock() if i.createPipelineProjectTriggerAccessTokenError { @@ -318,8 +319,8 @@ func (i *inMemoryClient) CreatePipelineProjectTriggerAccessToken(ctx context.Con i.internalCounter++ var tokenId = i.internalCounter key := fmt.Sprintf("%s_%v_%v", t.TypePipelineProjectTrigger.String(), projectId, tokenId) - var entryToken = &gitlab.TokenPipelineProjectTrigger{ - Token: gitlab.Token{ + var entryToken = &models.TokenPipelineProjectTrigger{ + Token: models.Token{ TokenID: tokenId, ParentID: strconv.Itoa(projectId), Path: strconv.Itoa(projectId), @@ -358,7 +359,7 @@ func (i *inMemoryClient) GitlabClient(ctx context.Context) *g.Client { return nil } -func (i *inMemoryClient) CreateGroupServiceAccountAccessToken(ctx context.Context, path string, groupId string, userId int, name string, expiresAt time.Time, scopes []string) (*gitlab.TokenGroupServiceAccount, error) { +func (i *inMemoryClient) CreateGroupServiceAccountAccessToken(ctx context.Context, path string, groupId string, userId int, name string, expiresAt time.Time, scopes []string) (*models.TokenGroupServiceAccount, error) { i.muLock.Lock() defer i.muLock.Unlock() if i.createGroupServiceAccountAccessTokenError { @@ -367,20 +368,20 @@ func (i *inMemoryClient) CreateGroupServiceAccountAccessToken(ctx context.Contex return nil, nil } -func (i *inMemoryClient) CreateUserServiceAccountAccessToken(ctx context.Context, username string, userId int, name string, expiresAt time.Time, scopes []string) (*gitlab.TokenUserServiceAccount, error) { +func (i *inMemoryClient) CreateUserServiceAccountAccessToken(ctx context.Context, username string, userId int, name string, expiresAt time.Time, scopes []string) (*models.TokenUserServiceAccount, error) { i.muLock.Lock() if i.createUserServiceAccountAccessTokenError { i.muLock.Unlock() return nil, fmt.Errorf("CreateUserServiceAccountAccessToken") } i.muLock.Unlock() - var tok *gitlab.TokenUserServiceAccount + var tok *models.TokenUserServiceAccount var err error - var cpat *gitlab.TokenPersonal + var cpat *models.TokenPersonal if cpat, err = i.CreatePersonalAccessToken(ctx, username, userId, name, expiresAt, scopes); err != nil && cpat != nil { - tok = &gitlab.TokenUserServiceAccount{ - TokenWithScopes: gitlab.TokenWithScopes{ - Token: gitlab.Token{ + tok = &models.TokenUserServiceAccount{ + TokenWithScopes: models.TokenWithScopes{ + Token: models.Token{ CreatedAt: cpat.CreatedAt, ExpiresAt: cpat.ExpiresAt, TokenType: t.TypeUserServiceAccount, @@ -418,14 +419,14 @@ func (i *inMemoryClient) RevokeGroupServiceAccountAccessToken(ctx context.Contex return nil } -func (i *inMemoryClient) CurrentTokenInfo(ctx context.Context) (*gitlab.TokenConfig, error) { +func (i *inMemoryClient) CurrentTokenInfo(ctx context.Context) (*models.TokenConfig, error) { i.muLock.Lock() defer i.muLock.Unlock() i.calledMainToken++ return &i.mainTokenInfo, nil } -func (i *inMemoryClient) RotateCurrentToken(ctx context.Context) (*gitlab.TokenConfig, *gitlab.TokenConfig, error) { +func (i *inMemoryClient) RotateCurrentToken(ctx context.Context) (*models.TokenConfig, *models.TokenConfig, error) { i.muLock.Lock() defer i.muLock.Unlock() i.calledRotateMainToken++ @@ -439,7 +440,7 @@ func (i *inMemoryClient) Valid(ctx context.Context) bool { return i.valid } -func (i *inMemoryClient) CreatePersonalAccessToken(ctx context.Context, username string, userId int, name string, expiresAt time.Time, scopes []string) (*gitlab.TokenPersonal, error) { +func (i *inMemoryClient) CreatePersonalAccessToken(ctx context.Context, username string, userId int, name string, expiresAt time.Time, scopes []string) (*models.TokenPersonal, error) { i.muLock.Lock() defer i.muLock.Unlock() if i.personalAccessTokenCreateError { @@ -447,9 +448,9 @@ func (i *inMemoryClient) CreatePersonalAccessToken(ctx context.Context, username } i.internalCounter++ var tokenId = i.internalCounter - var entryToken = &gitlab.TokenPersonal{ - TokenWithScopes: gitlab.TokenWithScopes{ - Token: gitlab.Token{ + var entryToken = &models.TokenPersonal{ + TokenWithScopes: models.TokenWithScopes{ + Token: models.Token{ TokenID: tokenId, ParentID: "", Path: username, @@ -467,7 +468,7 @@ func (i *inMemoryClient) CreatePersonalAccessToken(ctx context.Context, username return entryToken, nil } -func (i *inMemoryClient) CreateGroupAccessToken(ctx context.Context, groupId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (*gitlab.TokenGroup, error) { +func (i *inMemoryClient) CreateGroupAccessToken(ctx context.Context, groupId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (*models.TokenGroup, error) { i.muLock.Lock() defer i.muLock.Unlock() if i.groupAccessTokenCreateError { @@ -475,9 +476,9 @@ func (i *inMemoryClient) CreateGroupAccessToken(ctx context.Context, groupId str } i.internalCounter++ var tokenId = i.internalCounter - var entryToken = &gitlab.TokenGroup{ - TokenWithScopesAndAccessLevel: gitlab.TokenWithScopesAndAccessLevel{ - Token: gitlab.Token{ + var entryToken = &models.TokenGroup{ + TokenWithScopesAndAccessLevel: models.TokenWithScopesAndAccessLevel{ + Token: models.Token{ TokenID: tokenId, ParentID: groupId, Path: groupId, @@ -495,7 +496,7 @@ func (i *inMemoryClient) CreateGroupAccessToken(ctx context.Context, groupId str return entryToken, nil } -func (i *inMemoryClient) CreateProjectAccessToken(ctx context.Context, projectId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (*gitlab.TokenProject, error) { +func (i *inMemoryClient) CreateProjectAccessToken(ctx context.Context, projectId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (*models.TokenProject, error) { i.muLock.Lock() defer i.muLock.Unlock() if i.projectAccessTokenCreateError { @@ -503,9 +504,9 @@ func (i *inMemoryClient) CreateProjectAccessToken(ctx context.Context, projectId } i.internalCounter++ var tokenId = i.internalCounter - var entryToken = &gitlab.TokenProject{ - TokenWithScopesAndAccessLevel: gitlab.TokenWithScopesAndAccessLevel{ - Token: gitlab.Token{ + var entryToken = &models.TokenProject{ + TokenWithScopesAndAccessLevel: models.TokenWithScopesAndAccessLevel{ + Token: models.Token{ Token: fmt.Sprintf("glpat-%s", uuid.New().String()), TokenType: t.TypeProject, CreatedAt: g.Ptr(time.Now()), diff --git a/token.go b/internal/models/token.go similarity index 63% rename from token.go rename to internal/models/token.go index 5a71e7b..705b96c 100644 --- a/token.go +++ b/internal/models/token.go @@ -1,28 +1,19 @@ -package gitlab +package models import ( "crypto/sha1" "fmt" "maps" "strconv" + "strings" "time" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) -type IToken interface { - Internal() map[string]any - Data() map[string]any - Event(map[string]string) map[string]string - Type() token.Type - SetConfigName(string) - SetRoleName(string) - SetGitlabRevokesToken(bool) - SetExpiresAt(*time.Time) - GetExpiresAt() time.Time - GetCreatedAt() time.Time - TTL() time.Duration -} +var _ token.Token = (*Token)(nil) +var _ token.Token = (*TokenWithScopes)(nil) +var _ token.Token = (*TokenWithScopesAndAccessLevel)(nil) type Token struct { RoleName string `json:"role_name"` @@ -106,4 +97,60 @@ func (t *Token) Event(m map[string]string) (d map[string]string) { return d } -var _ IToken = (*Token)(nil) +type TokenWithScopes struct { + Token `json:",inline"` + + Scopes []string `json:"scopes"` +} + +func (t *TokenWithScopes) Internal() (d map[string]any) { + d = map[string]any{"scopes": t.Scopes} + maps.Copy(d, t.Token.Internal()) + return d +} + +func (t *TokenWithScopes) Data() (d map[string]any) { + d = map[string]any{"scopes": t.Scopes} + maps.Copy(d, t.Token.Data()) + return d +} + +func (t *TokenWithScopes) Event(m map[string]string) (d map[string]string) { + d = map[string]string{"scopes": strings.Join(t.Scopes, ",")} + maps.Copy(d, t.Token.Event(m)) + return d +} + +type TokenWithScopesAndAccessLevel struct { + Token `json:",inline"` + + Scopes []string `json:"scopes"` + AccessLevel token.AccessLevel `json:"access_level"` +} + +func (t *TokenWithScopesAndAccessLevel) Internal() (d map[string]any) { + d = map[string]any{ + "scopes": t.Scopes, + "access_level": t.AccessLevel.String(), + } + maps.Copy(d, t.Token.Internal()) + return d +} + +func (t *TokenWithScopesAndAccessLevel) Data() (d map[string]any) { + d = map[string]any{ + "scopes": t.Scopes, + "access_level": t.AccessLevel.String(), + } + maps.Copy(d, t.Token.Data()) + return d +} + +func (t *TokenWithScopesAndAccessLevel) Event(m map[string]string) (d map[string]string) { + d = map[string]string{ + "scopes": strings.Join(t.Scopes, ","), + "access_level": t.AccessLevel.String(), + } + maps.Copy(d, t.Token.Event(m)) + return d +} diff --git a/internal/models/token_config.go b/internal/models/token_config.go new file mode 100644 index 0000000..2d22c45 --- /dev/null +++ b/internal/models/token_config.go @@ -0,0 +1,34 @@ +package models + +import ( + "maps" + "strconv" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" +) + +type TokenConfig struct { + TokenWithScopes `json:",inline"` + + UserID int `json:"user_id"` +} + +func (t *TokenConfig) Internal() (d map[string]any) { + d = map[string]any{"user_id": t.UserID} + maps.Copy(d, t.TokenWithScopes.Internal()) + return d +} + +func (t *TokenConfig) Data() (d map[string]any) { + d = map[string]any{"user_id": t.UserID} + maps.Copy(d, t.TokenWithScopes.Data()) + return d +} + +func (t *TokenConfig) Event(m map[string]string) (d map[string]string) { + d = map[string]string{"user_id": strconv.Itoa(t.UserID)} + maps.Copy(d, t.Token.Event(m)) + return d +} + +var _ token.Token = (*TokenConfig)(nil) diff --git a/internal/models/token_config_test.go b/internal/models/token_config_test.go new file mode 100644 index 0000000..88f82e4 --- /dev/null +++ b/internal/models/token_config_test.go @@ -0,0 +1,19 @@ +package models_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/models" +) + +func TestTokenConfig(t *testing.T) { + data := models.TokenConfig{UserID: 1} + assert.Contains(t, data.Data(), "user_id") + assert.Contains(t, data.Event(nil), "user_id") + assert.Contains(t, data.Internal(), "user_id") + assert.EqualValues(t, 1, data.Data()["user_id"]) + assert.EqualValues(t, "1", data.Event(nil)["user_id"]) + assert.EqualValues(t, 1, data.Internal()["user_id"]) +} diff --git a/internal/models/token_group.go b/internal/models/token_group.go new file mode 100644 index 0000000..85a3097 --- /dev/null +++ b/internal/models/token_group.go @@ -0,0 +1,9 @@ +package models + +import "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" + +type TokenGroup struct { + TokenWithScopesAndAccessLevel `json:",inline"` +} + +var _ token.Token = (*TokenGroup)(nil) diff --git a/token_group_deploy.go b/internal/models/token_group_deploy.go similarity index 82% rename from token_group_deploy.go rename to internal/models/token_group_deploy.go index ec1f149..773c55f 100644 --- a/token_group_deploy.go +++ b/internal/models/token_group_deploy.go @@ -1,7 +1,9 @@ -package gitlab +package models import ( "maps" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) type TokenGroupDeploy struct { @@ -27,3 +29,5 @@ func (t *TokenGroupDeploy) Event(m map[string]string) (d map[string]string) { maps.Copy(d, t.Token.Event(m)) return d } + +var _ token.Token = (*TokenGroupDeploy)(nil) diff --git a/internal/models/token_group_deploy_test.go b/internal/models/token_group_deploy_test.go new file mode 100644 index 0000000..67e5153 --- /dev/null +++ b/internal/models/token_group_deploy_test.go @@ -0,0 +1,19 @@ +package models_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/models" +) + +func TestTokenGroupDeploy(t *testing.T) { + data := models.TokenGroupDeploy{Username: "username"} + assert.Contains(t, data.Data(), "username") + assert.Contains(t, data.Event(nil), "username") + assert.Contains(t, data.Internal(), "username") + assert.EqualValues(t, "username", data.Data()["username"]) + assert.EqualValues(t, "username", data.Event(nil)["username"]) + assert.EqualValues(t, "username", data.Internal()["username"]) +} diff --git a/token_group_service_account.go b/internal/models/token_group_service_account.go similarity index 82% rename from token_group_service_account.go rename to internal/models/token_group_service_account.go index 4c8531d..9dfa886 100644 --- a/token_group_service_account.go +++ b/internal/models/token_group_service_account.go @@ -1,8 +1,10 @@ -package gitlab +package models import ( "maps" "strconv" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) type TokenGroupServiceAccount struct { @@ -28,3 +30,5 @@ func (t *TokenGroupServiceAccount) Event(m map[string]string) (d map[string]stri maps.Copy(d, t.Token.Event(m)) return d } + +var _ token.Token = (*TokenGroupServiceAccount)(nil) diff --git a/internal/models/token_group_service_account_test.go b/internal/models/token_group_service_account_test.go new file mode 100644 index 0000000..f83f563 --- /dev/null +++ b/internal/models/token_group_service_account_test.go @@ -0,0 +1,19 @@ +package models_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/models" +) + +func TestTokenGroupServiceAccount(t *testing.T) { + data := models.TokenGroupServiceAccount{UserID: 1} + assert.Contains(t, data.Data(), "user_id") + assert.Contains(t, data.Event(nil), "user_id") + assert.Contains(t, data.Internal(), "user_id") + assert.EqualValues(t, 1, data.Data()["user_id"]) + assert.EqualValues(t, "1", data.Event(nil)["user_id"]) + assert.EqualValues(t, 1, data.Internal()["user_id"]) +} diff --git a/token_personal.go b/internal/models/token_personal.go similarity index 82% rename from token_personal.go rename to internal/models/token_personal.go index afa8e53..30608fa 100644 --- a/token_personal.go +++ b/internal/models/token_personal.go @@ -1,8 +1,10 @@ -package gitlab +package models import ( "maps" "strconv" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" ) type TokenPersonal struct { @@ -28,3 +30,5 @@ func (t *TokenPersonal) Event(m map[string]string) (d map[string]string) { maps.Copy(d, t.Token.Event(m)) return d } + +var _ token.Token = (*TokenPersonal)(nil) diff --git a/internal/models/token_personal_test.go b/internal/models/token_personal_test.go new file mode 100644 index 0000000..a7a306a --- /dev/null +++ b/internal/models/token_personal_test.go @@ -0,0 +1,19 @@ +package models_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/models" +) + +func TestTokenPersonal(t *testing.T) { + data := models.TokenPersonal{UserID: 1} + assert.Contains(t, data.Data(), "user_id") + assert.Contains(t, data.Event(nil), "user_id") + assert.Contains(t, data.Internal(), "user_id") + assert.EqualValues(t, 1, data.Data()["user_id"]) + assert.EqualValues(t, "1", data.Event(nil)["user_id"]) + assert.EqualValues(t, 1, data.Internal()["user_id"]) +} diff --git a/internal/models/token_pipeline_project_trigger.go b/internal/models/token_pipeline_project_trigger.go new file mode 100644 index 0000000..62fc427 --- /dev/null +++ b/internal/models/token_pipeline_project_trigger.go @@ -0,0 +1,9 @@ +package models + +import "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" + +type TokenPipelineProjectTrigger struct { + Token `json:",inline"` +} + +var _ token.Token = (*TokenPipelineProjectTrigger)(nil) diff --git a/internal/models/token_project.go b/internal/models/token_project.go new file mode 100644 index 0000000..04c451e --- /dev/null +++ b/internal/models/token_project.go @@ -0,0 +1,9 @@ +package models + +import "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" + +type TokenProject struct { + TokenWithScopesAndAccessLevel `json:",inline"` +} + +var _ token.Token = (*TokenProject)(nil) diff --git a/token_project_deploy.go b/internal/models/token_project_deploy.go similarity index 80% rename from token_project_deploy.go rename to internal/models/token_project_deploy.go index fdb987a..c5be3ea 100644 --- a/token_project_deploy.go +++ b/internal/models/token_project_deploy.go @@ -1,6 +1,10 @@ -package gitlab +package models -import "maps" +import ( + "maps" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" +) type TokenProjectDeploy struct { TokenWithScopes `json:",inline"` @@ -25,3 +29,5 @@ func (t *TokenProjectDeploy) Event(m map[string]string) (d map[string]string) { maps.Copy(d, t.Token.Event(m)) return d } + +var _ token.Token = (*TokenProjectDeploy)(nil) diff --git a/internal/models/token_project_deploy_test.go b/internal/models/token_project_deploy_test.go new file mode 100644 index 0000000..191388d --- /dev/null +++ b/internal/models/token_project_deploy_test.go @@ -0,0 +1,19 @@ +package models_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/models" +) + +func TestTokenProjectDeploy(t *testing.T) { + data := models.TokenProjectDeploy{Username: "username"} + assert.Contains(t, data.Data(), "username") + assert.Contains(t, data.Event(nil), "username") + assert.Contains(t, data.Internal(), "username") + assert.EqualValues(t, "username", data.Data()["username"]) + assert.EqualValues(t, "username", data.Event(nil)["username"]) + assert.EqualValues(t, "username", data.Internal()["username"]) +} diff --git a/internal/models/token_test.go b/internal/models/token_test.go new file mode 100644 index 0000000..d75c9eb --- /dev/null +++ b/internal/models/token_test.go @@ -0,0 +1,68 @@ +package models_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/models" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" +) + +func TestToken(t *testing.T) { + t.Run("expires is not set so we get a 0 ttl", func(t *testing.T) { + data := models.Token{} + require.EqualValues(t, 0, data.TTL()) + }) + + t.Run("ttl has a value if both created and expires are set", func(t *testing.T) { + cat := time.Date(2025, 1, 1, 1, 0, 0, 0, time.UTC) + data := models.Token{CreatedAt: &cat} + eat := time.Date(2025, 1, 1, 2, 0, 0, 0, time.UTC) + data.SetExpiresAt(&eat) + require.EqualValues(t, time.Hour, data.TTL()) + }) + + t.Run("setters", func(t *testing.T) { + data := models.Token{} + data.SetRoleName("role-name") + data.SetConfigName("config-name") + data.SetGitlabRevokesToken(true) + + require.EqualValues(t, "role-name", data.RoleName) + require.EqualValues(t, "config-name", data.ConfigName) + require.EqualValues(t, true, data.GitlabRevokesToken) + + }) +} + +func TestTokenWithScopes(t *testing.T) { + data := models.TokenWithScopes{Scopes: []string{"scope1", "scope2"}} + assert.Contains(t, data.Data(), "scopes") + assert.Contains(t, data.Event(nil), "scopes") + assert.Contains(t, data.Internal(), "scopes") + assert.EqualValues(t, []string{"scope1", "scope2"}, data.Data()["scopes"]) + assert.EqualValues(t, "scope1,scope2", data.Event(nil)["scopes"]) + assert.EqualValues(t, []string{"scope1", "scope2"}, data.Internal()["scopes"]) +} + +func TestTokenWithScopesAndAccessLevel(t *testing.T) { + data := models.TokenWithScopesAndAccessLevel{ + Scopes: []string{"scope1", "scope2"}, + AccessLevel: token.AccessLevelNoPermissions, + } + assert.Contains(t, data.Data(), "scopes") + assert.Contains(t, data.Event(nil), "scopes") + assert.Contains(t, data.Internal(), "scopes") + assert.EqualValues(t, []string{"scope1", "scope2"}, data.Data()["scopes"]) + assert.EqualValues(t, "scope1,scope2", data.Event(nil)["scopes"]) + assert.EqualValues(t, []string{"scope1", "scope2"}, data.Internal()["scopes"]) + assert.Contains(t, data.Data(), "access_level") + assert.Contains(t, data.Event(nil), "access_level") + assert.Contains(t, data.Internal(), "access_level") + assert.EqualValues(t, token.AccessLevelNoPermissions, data.Data()["access_level"]) + assert.EqualValues(t, token.AccessLevelNoPermissions, data.Event(nil)["access_level"]) + assert.EqualValues(t, token.AccessLevelNoPermissions, data.Internal()["access_level"]) +} diff --git a/internal/models/token_user_service_account.go b/internal/models/token_user_service_account.go new file mode 100644 index 0000000..5a28df1 --- /dev/null +++ b/internal/models/token_user_service_account.go @@ -0,0 +1,9 @@ +package models + +import "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" + +type TokenUserServiceAccount struct { + TokenWithScopes `json:",inline"` +} + +var _ token.Token = (*TokenUserServiceAccount)(nil) diff --git a/internal/token/token.go b/internal/token/token.go new file mode 100644 index 0000000..6ef104e --- /dev/null +++ b/internal/token/token.go @@ -0,0 +1,19 @@ +package token + +import ( + "time" +) + +type Token interface { + Internal() map[string]any + Data() map[string]any + Event(map[string]string) map[string]string + Type() Type + SetConfigName(string) + SetRoleName(string) + SetGitlabRevokesToken(bool) + SetExpiresAt(*time.Time) + GetExpiresAt() time.Time + GetCreatedAt() time.Time + TTL() time.Duration +} diff --git a/path_config.go b/path_config.go index 281335b..f302dab 100644 --- a/path_config.go +++ b/path_config.go @@ -15,6 +15,7 @@ import ( "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/event" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/models" ) const ( @@ -156,7 +157,7 @@ func (b *Backend) pathConfigPatch(ctx context.Context, req *logical.Request, dat return lResp, err } -func (b *Backend) updateConfigClientInfo(ctx context.Context, config *EntryConfig) (et *TokenConfig, err error) { +func (b *Backend) updateConfigClientInfo(ctx context.Context, config *EntryConfig) (et *models.TokenConfig, err error) { var httpClient *http.Client var client Client httpClient, _ = HttpClientFromContext(ctx) diff --git a/path_config_rotate.go b/path_config_rotate.go index 195f8ff..595590c 100644 --- a/path_config_rotate.go +++ b/path_config_rotate.go @@ -13,6 +13,7 @@ import ( "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/event" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/models" ) const pathConfigRotateHelpSynopsis = `Rotate the gitlab token for this configuration.` @@ -80,7 +81,7 @@ func (b *Backend) pathConfigTokenRotate(ctx context.Context, request *logical.Re return nil, err } - var entryToken *TokenConfig + var entryToken *models.TokenConfig entryToken, _, err = client.RotateCurrentToken(ctx) if err != nil { b.Logger().Error("Failed to rotate main token", "err", err) diff --git a/path_token_role.go b/path_token_role.go index e41c72b..ac05b4c 100644 --- a/path_token_role.go +++ b/path_token_role.go @@ -61,7 +61,7 @@ func (b *Backend) pathTokenRoleCreate(ctx context.Context, req *logical.Request, defer b.Logger().Debug("Created token for role", "role_name", roleName, "token_type", role.TokenType.String()) var name string - var token IToken + var token token2.Token var expiresAt time.Time var startTime = TimeFromContext(ctx).UTC() diff --git a/token_config.go b/token_config.go deleted file mode 100644 index 16f791a..0000000 --- a/token_config.go +++ /dev/null @@ -1,7 +0,0 @@ -package gitlab - -type TokenConfig struct { - TokenWithScopes `json:",inline"` - - UserID int `json:"user_id"` -} diff --git a/token_group.go b/token_group.go deleted file mode 100644 index 86c10af..0000000 --- a/token_group.go +++ /dev/null @@ -1,5 +0,0 @@ -package gitlab - -type TokenGroup struct { - TokenWithScopesAndAccessLevel `json:",inline"` -} diff --git a/token_pipeline_project_trigger.go b/token_pipeline_project_trigger.go deleted file mode 100644 index 81131c8..0000000 --- a/token_pipeline_project_trigger.go +++ /dev/null @@ -1,5 +0,0 @@ -package gitlab - -type TokenPipelineProjectTrigger struct { - Token `json:",inline"` -} diff --git a/token_project.go b/token_project.go deleted file mode 100644 index 99e28a4..0000000 --- a/token_project.go +++ /dev/null @@ -1,5 +0,0 @@ -package gitlab - -type TokenProject struct { - TokenWithScopesAndAccessLevel `json:",inline"` -} diff --git a/token_user_service_account.go b/token_user_service_account.go deleted file mode 100644 index f3db5f0..0000000 --- a/token_user_service_account.go +++ /dev/null @@ -1,5 +0,0 @@ -package gitlab - -type TokenUserServiceAccount struct { - TokenWithScopes `json:",inline"` -} diff --git a/token_with_scopes.go b/token_with_scopes.go deleted file mode 100644 index d3a7ced..0000000 --- a/token_with_scopes.go +++ /dev/null @@ -1,32 +0,0 @@ -package gitlab - -import ( - "maps" - "strings" -) - -type TokenWithScopes struct { - Token `json:",inline"` - - Scopes []string `json:"scopes"` -} - -func (t *TokenWithScopes) Internal() (d map[string]any) { - d = map[string]any{"scopes": t.Scopes} - maps.Copy(d, t.Token.Internal()) - return d -} - -func (t *TokenWithScopes) Data() (d map[string]any) { - d = map[string]any{"scopes": t.Scopes} - maps.Copy(d, t.Token.Data()) - return d -} - -func (t *TokenWithScopes) Event(m map[string]string) (d map[string]string) { - d = map[string]string{"scopes": strings.Join(t.Scopes, ",")} - maps.Copy(d, t.Token.Event(m)) - return d -} - -var _ IToken = (*TokenWithScopes)(nil) diff --git a/token_with_scopes_and_access_level.go b/token_with_scopes_and_access_level.go deleted file mode 100644 index 7acabf8..0000000 --- a/token_with_scopes_and_access_level.go +++ /dev/null @@ -1,44 +0,0 @@ -package gitlab - -import ( - "maps" - "strings" - - "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" -) - -type TokenWithScopesAndAccessLevel struct { - Token `json:",inline"` - - Scopes []string `json:"scopes"` - AccessLevel token.AccessLevel `json:"access_level"` -} - -func (t *TokenWithScopesAndAccessLevel) Internal() (d map[string]any) { - d = map[string]any{ - "scopes": t.Scopes, - "access_level": t.AccessLevel.String(), - } - maps.Copy(d, t.Token.Internal()) - return d -} - -func (t *TokenWithScopesAndAccessLevel) Data() (d map[string]any) { - d = map[string]any{ - "scopes": t.Scopes, - "access_level": t.AccessLevel.String(), - } - maps.Copy(d, t.Token.Data()) - return d -} - -func (t *TokenWithScopesAndAccessLevel) Event(m map[string]string) (d map[string]string) { - d = map[string]string{ - "scopes": strings.Join(t.Scopes, ","), - "access_level": t.AccessLevel.String(), - } - maps.Copy(d, t.Token.Event(m)) - return d -} - -var _ IToken = (*TokenWithScopesAndAccessLevel)(nil) From 6da9ad4db7f2dfdb4a2d6c47f2a2930fc5714454 Mon Sep 17 00:00:00 2001 From: Ilija Matoski Date: Sun, 22 Jun 2025 21:04:07 +0200 Subject: [PATCH 12/17] fix golangci-lint errors --- path_config.go | 6 +++--- path_config_rotate.go | 2 +- path_flags.go | 2 +- path_role.go | 4 ++-- path_token_role.go | 2 +- secret_access_tokens.go | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/path_config.go b/path_config.go index f302dab..2d2fe54 100644 --- a/path_config.go +++ b/path_config.go @@ -93,7 +93,7 @@ func (b *Backend) pathConfigDelete(ctx context.Context, req *logical.Request, da } if err = req.Storage.Delete(ctx, fmt.Sprintf("%s/%s", PathConfigStorage, name)); err == nil { - event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "config-delete", map[string]string{ + _ = event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "config-delete", map[string]string{ "path": fmt.Sprintf("%s/%s", PathConfigStorage, name), }) b.SetClient(nil, name) @@ -148,7 +148,7 @@ func (b *Backend) pathConfigPatch(ctx context.Context, req *logical.Request, dat defer b.lockClientMutex.Unlock() if err = saveConfig(ctx, *config, req.Storage); err == nil { lrd := config.LogicalResponseData(b.flags.ShowConfigToken) - event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "config-patch", changes) + _ = event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "config-patch", changes) b.SetClient(nil, name) b.Logger().Debug("Patched config", "lrd", lrd, "warnings", warnings) lResp = &logical.Response{Data: lrd, Warnings: warnings} @@ -207,7 +207,7 @@ func (b *Backend) pathConfigWrite(ctx context.Context, req *logical.Request, dat var lResp *logical.Response if err = saveConfig(ctx, *config, req.Storage); err == nil { - event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "config-write", map[string]string{ + _ = event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "config-write", map[string]string{ "path": fmt.Sprintf("%s/%s", PathConfigStorage, name), "auto_rotate_token": strconv.FormatBool(config.AutoRotateToken), "auto_rotate_before": config.AutoRotateBefore.String(), diff --git a/path_config_rotate.go b/path_config_rotate.go index 595590c..a810c50 100644 --- a/path_config_rotate.go +++ b/path_config_rotate.go @@ -107,7 +107,7 @@ func (b *Backend) pathConfigTokenRotate(ctx context.Context, request *logical.Re lResp = &logical.Response{Data: config.LogicalResponseData(b.flags.ShowConfigToken)} lResp.Data["token"] = config.Token - event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "config-token-rotate", map[string]string{ + _ = event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "config-token-rotate", map[string]string{ "path": fmt.Sprintf("%s/%s", PathConfigStorage, name), "expires_at": entryToken.ExpiresAt.Format(time.RFC3339), "created_at": entryToken.CreatedAt.Format(time.RFC3339), diff --git a/path_flags.go b/path_flags.go index a0102a0..ededa5c 100644 --- a/path_flags.go +++ b/path_flags.go @@ -45,7 +45,7 @@ func (b *Backend) pathFlagsUpdate(ctx context.Context, req *logical.Request, dat eventData["show_config_token"] = strconv.FormatBool(b.flags.ShowConfigToken) } - event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "flags-write", eventData) + _ = event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "flags-write", eventData) var flagData map[string]any err = mapstructure.Decode(b.flags, &flagData) diff --git a/path_role.go b/path_role.go index 96b657b..a38b087 100644 --- a/path_role.go +++ b/path_role.go @@ -167,7 +167,7 @@ func (b *Backend) pathRolesDelete(ctx context.Context, req *logical.Request, dat return nil, fmt.Errorf("error deleting role: %w", err) } - event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "role-delete", map[string]string{ + _ = event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "role-delete", map[string]string{ "path": "roles", "role_name": roleName, }) @@ -371,7 +371,7 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data return nil, err } - event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "role-write", map[string]string{ + _ = event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "role-write", map[string]string{ "path": "roles", "role_name": roleName, "config_name": role.ConfigName, diff --git a/path_token_role.go b/path_token_role.go index ac05b4c..42ca317 100644 --- a/path_token_role.go +++ b/path_token_role.go @@ -156,7 +156,7 @@ func (b *Backend) pathTokenRoleCreate(ctx context.Context, req *logical.Request, resp.Secret.TTL = token.TTL() } - event.Event( + _ = event.Event( ctx, b.Backend, operationPrefixGitlabAccessTokens, "token-write", token.Event(map[string]string{"path": fmt.Sprintf("%s/%s", PathRoleStorage, roleName)}), ) diff --git a/secret_access_tokens.go b/secret_access_tokens.go index 633978f..1fe7aff 100644 --- a/secret_access_tokens.go +++ b/secret_access_tokens.go @@ -128,7 +128,7 @@ func (b *Backend) secretAccessTokenRevoke(ctx context.Context, req *logical.Requ } } - event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "token-revoke", map[string]string{ + _ = event.Event(ctx, b.Backend, operationPrefixGitlabAccessTokens, "token-revoke", map[string]string{ "lease_id": secret.LeaseID, "path": req.Secret.InternalData["path"].(string), "name": req.Secret.InternalData["name"].(string), From 3e775ea5050cd217d3ed205eec558e6a5442cd1e Mon Sep 17 00:00:00 2001 From: Ilija Matoski Date: Tue, 12 Aug 2025 09:26:35 +0200 Subject: [PATCH 13/17] move name templates to internal/utils --- entry_role.go | 8 ++ go.sum | 2 + name_tpl.go => internal/utils/name_tpl.go | 22 +++- internal/utils/name_tpl_test.go | 137 ++++++++++++++++++++++ name_tpl_rand_string_test.go | 31 ----- name_tpl_test.go | 99 ---------------- name_tpl_unix_timestamp_test.go | 35 ------ path_role.go | 3 +- path_token_role.go | 2 +- 9 files changed, 167 insertions(+), 172 deletions(-) rename name_tpl.go => internal/utils/name_tpl.go (64%) create mode 100644 internal/utils/name_tpl_test.go delete mode 100644 name_tpl_rand_string_test.go delete mode 100644 name_tpl_test.go delete mode 100644 name_tpl_unix_timestamp_test.go diff --git a/entry_role.go b/entry_role.go index 0ef70d9..c9feaa3 100644 --- a/entry_role.go +++ b/entry_role.go @@ -22,6 +22,14 @@ type EntryRole struct { ConfigName string `json:"config_name" structs:"config_name" mapstructure:"config_name"` } +func (e EntryRole) IsNil() bool { + return false +} + +func (e EntryRole) GetName() string { + return e.Name +} + func (e EntryRole) LogicalResponseData() map[string]any { return map[string]any{ "role_name": e.RoleName, diff --git a/go.sum b/go.sum index be62d2d..01ae9c8 100644 --- a/go.sum +++ b/go.sum @@ -626,6 +626,8 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/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= +gopkg.in/dnaeon/go-vcr.v4 v4.0.2 h1:7T5VYf2ifyK01ETHbJPl5A6XTpUljD4Trw3GEDcdedk= +gopkg.in/dnaeon/go-vcr.v4 v4.0.2/go.mod h1:65yxh9goQVrudqofKtHA4JNFWd6XZRkWfKN4YpMx7KI= gopkg.in/dnaeon/go-vcr.v4 v4.0.3 h1:rlSB7VRNGo90rqbNWA3+/3iftkjLEvcf3bhkAULqE0o= gopkg.in/dnaeon/go-vcr.v4 v4.0.3/go.mod h1:65yxh9goQVrudqofKtHA4JNFWd6XZRkWfKN4YpMx7KI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= diff --git a/name_tpl.go b/internal/utils/name_tpl.go similarity index 64% rename from name_tpl.go rename to internal/utils/name_tpl.go index 9005e56..83898c6 100644 --- a/name_tpl.go +++ b/internal/utils/name_tpl.go @@ -1,4 +1,4 @@ -package gitlab +package utils import ( "crypto/rand" @@ -34,12 +34,26 @@ var tplFuncMap = template.FuncMap{ "timeNowFormat": timeNowFormat, } -func TokenName(role *EntryRole) (name string, err error) { - if role == nil { +type TokenNameData interface { + GetName() string + LogicalResponseData() map[string]any + IsNil() bool +} + +func ValidateTokenNameName(role TokenNameData) (err error) { + if role == nil || role.IsNil() { + return fmt.Errorf("role: %w", errs.ErrNilValue) + } + _, err = template.New("name").Funcs(tplFuncMap).Parse(role.GetName()) + return err +} + +func TokenName(role TokenNameData) (name string, err error) { + if role == nil || role.IsNil() { return "", fmt.Errorf("role: %w", errs.ErrNilValue) } var tpl *template.Template - tpl, err = template.New("name").Funcs(tplFuncMap).Parse(role.Name) + tpl, err = template.New("name").Funcs(tplFuncMap).Parse(role.GetName()) if err != nil { return "", err } diff --git a/internal/utils/name_tpl_test.go b/internal/utils/name_tpl_test.go new file mode 100644 index 0000000..9ca66e9 --- /dev/null +++ b/internal/utils/name_tpl_test.go @@ -0,0 +1,137 @@ +package utils_test + +import ( + "fmt" + "strconv" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" +) + +type tokenName struct { + name string + data map[string]any +} + +func (t *tokenName) IsNil() bool { + return t == nil +} + +func (t *tokenName) GetName() string { + return t.name +} + +func (t *tokenName) LogicalResponseData() map[string]any { + if t.data == nil { + return make(map[string]any) + } + return t.data +} + +var _ utils.TokenNameData = (*tokenName)(nil) + +func TestTokenNameGenerator(t *testing.T) { + var tests = []struct { + in *tokenName + outVal string + outErr bool + }{ + {nil, "", true}, + + // invalid template + { + &tokenName{ + name: "{{ .role_name", + }, + "", + true, + }, + + // combination template + { + &tokenName{ + name: "{{ .role_name }}-{{ .token_type }}-access-token-{{ yesNoBool .gitlab_revokes_token }}", + data: map[string]any{ + "role_name": "test", + "token_type": "personal", + "gitlab_revokes_token": true, + }, + }, + "test-personal-access-token-yes", + false, + }, + + // with stringsJoin + { + &tokenName{ + name: "{{ .role_name }}-{{ .token_type }}-{{ stringsJoin .scopes \"-\" }}-{{ yesNoBool .gitlab_revokes_token }}", + data: map[string]any{ + "role_name": "test", + "token_type": "personal", + "scopes": []string{"api", "sudo"}, + "gitlab_revokes_token": false, + }, + }, + "test-personal-api-sudo-no", + false, + }, + + // with timeNowFormat + { + &tokenName{ + name: "{{ .role_name }}-{{ .token_type }}-{{ timeNowFormat \"2006-01\" }}", + data: map[string]any{ + "role_name": "test", + "token_type": "personal", + }, + }, + fmt.Sprintf("test-personal-%d-%02d", time.Now().UTC().Year(), time.Now().UTC().Month()), + false, + }, + } + + for _, tst := range tests { + t.Logf("TokenName(%v)", tst.in) + val, err := utils.TokenName(tst.in) + assert.Equal(t, tst.outVal, val) + if tst.outErr { + assert.Error(t, err, tst.outErr) + } else { + assert.NoError(t, err) + } + } +} + +func TestValidateTokenNameName(t *testing.T) { + require.Error(t, utils.ValidateTokenNameName(&tokenName{name: "{{ .name"})) + require.Error(t, utils.ValidateTokenNameName(nil)) +} + +func TestTokenNameGenerator_RandString(t *testing.T) { + val, err := utils.TokenName( + &tokenName{ + name: "{{ randHexString 8 }}", + }, + ) + require.NoError(t, err) + require.NotEmpty(t, val) + require.Len(t, val, 16) +} + +func TestTokenNameGenerator_UnixTimeStamp(t *testing.T) { + now := time.Now().UTC().Unix() + val, err := utils.TokenName( + &tokenName{ + name: "{{ .unix_timestamp_utc }}", + }, + ) + require.NoError(t, err) + require.NotEmpty(t, val) + i, err := strconv.ParseInt(val, 10, 64) + require.NoError(t, err) + require.GreaterOrEqual(t, i, now) +} diff --git a/name_tpl_rand_string_test.go b/name_tpl_rand_string_test.go deleted file mode 100644 index 45e74c9..0000000 --- a/name_tpl_rand_string_test.go +++ /dev/null @@ -1,31 +0,0 @@ -//go:build unit - -package gitlab_test - -import ( - "testing" - "time" - - "github.com/stretchr/testify/require" - - g "github.com/ilijamt/vault-plugin-secrets-gitlab" - "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" -) - -func TestTokenNameGenerator_RandString(t *testing.T) { - val, err := g.TokenName( - &g.EntryRole{ - RoleName: "test", - TTL: time.Hour, - Path: "/path", - Name: "{{ randHexString 8 }}", - Scopes: []string{token.ScopeApi.String()}, - AccessLevel: token.AccessLevelNoPermissions, - TokenType: token.TypePersonal, - GitlabRevokesTokens: false, - }, - ) - require.NoError(t, err) - require.NotEmpty(t, val) - require.Len(t, val, 16) -} diff --git a/name_tpl_test.go b/name_tpl_test.go deleted file mode 100644 index 34b9298..0000000 --- a/name_tpl_test.go +++ /dev/null @@ -1,99 +0,0 @@ -//go:build unit - -package gitlab_test - -import ( - "fmt" - "testing" - "time" - - "github.com/stretchr/testify/assert" - - g "github.com/ilijamt/vault-plugin-secrets-gitlab" - "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" -) - -func TestTokenNameGenerator(t *testing.T) { - var tests = []struct { - in *g.EntryRole - outVal string - outErr bool - }{ - {nil, "", true}, - - // invalid template - { - &g.EntryRole{ - RoleName: "test", - TTL: time.Hour, - Path: "/path", - Name: "{{ .role_name", - Scopes: []string{token.ScopeApi.String()}, - AccessLevel: token.AccessLevelNoPermissions, - TokenType: token.TypePersonal, - GitlabRevokesTokens: true, - }, - "", - true, - }, - - // combination template - { - &g.EntryRole{ - RoleName: "test", - TTL: time.Hour, - Path: "/path", - Name: "{{ .role_name }}-{{ .token_type }}-access-token-{{ yesNoBool .gitlab_revokes_token }}", - Scopes: []string{token.ScopeApi.String()}, - AccessLevel: token.AccessLevelNoPermissions, - TokenType: token.TypePersonal, - GitlabRevokesTokens: true, - }, - "test-personal-access-token-yes", - false, - }, - - // with stringsJoin - { - &g.EntryRole{ - RoleName: "test", - TTL: time.Hour, - Path: "/path", - Name: "{{ .role_name }}-{{ .token_type }}-{{ stringsJoin .scopes \"-\" }}-{{ yesNoBool .gitlab_revokes_token }}", - Scopes: []string{token.ScopeApi.String(), token.ScopeSudo.String()}, - AccessLevel: token.AccessLevelNoPermissions, - TokenType: token.TypePersonal, - GitlabRevokesTokens: false, - }, - "test-personal-api-sudo-no", - false, - }, - - // with timeNowFormat - { - &g.EntryRole{ - RoleName: "test", - TTL: time.Hour, - Path: "/path", - Name: "{{ .role_name }}-{{ .token_type }}-{{ timeNowFormat \"2006-01\" }}", - Scopes: []string{token.ScopeApi.String(), token.ScopeSudo.String()}, - AccessLevel: token.AccessLevelNoPermissions, - TokenType: token.TypePersonal, - GitlabRevokesTokens: false, - }, - fmt.Sprintf("test-personal-%d-%02d", time.Now().UTC().Year(), time.Now().UTC().Month()), - false, - }, - } - - for _, tst := range tests { - t.Logf("TokenName(%v)", tst.in) - val, err := g.TokenName(tst.in) - assert.Equal(t, tst.outVal, val) - if tst.outErr { - assert.Error(t, err, tst.outErr) - } else { - assert.NoError(t, err) - } - } -} diff --git a/name_tpl_unix_timestamp_test.go b/name_tpl_unix_timestamp_test.go deleted file mode 100644 index 12715c9..0000000 --- a/name_tpl_unix_timestamp_test.go +++ /dev/null @@ -1,35 +0,0 @@ -//go:build unit - -package gitlab_test - -import ( - "strconv" - "testing" - "time" - - "github.com/stretchr/testify/require" - - g "github.com/ilijamt/vault-plugin-secrets-gitlab" - "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" -) - -func TestTokenNameGenerator_UnixTimeStamp(t *testing.T) { - now := time.Now().UTC().Unix() - val, err := g.TokenName( - &g.EntryRole{ - RoleName: "test", - TTL: time.Hour, - Path: "/path", - Name: "{{ .unix_timestamp_utc }}", - Scopes: []string{token.ScopeApi.String()}, - AccessLevel: token.AccessLevelNoPermissions, - TokenType: token.TypePersonal, - GitlabRevokesTokens: false, - }, - ) - require.NoError(t, err) - require.NotEmpty(t, val) - i, err := strconv.ParseInt(val, 10, 64) - require.NoError(t, err) - require.GreaterOrEqual(t, i, now) -} diff --git a/path_role.go b/path_role.go index a38b087..e0a651d 100644 --- a/path_role.go +++ b/path_role.go @@ -7,7 +7,6 @@ import ( "net/http" "slices" "strings" - "text/template" "time" "github.com/hashicorp/go-multierror" @@ -236,7 +235,7 @@ func (b *Backend) pathRolesWrite(ctx context.Context, req *logical.Request, data } // validate name of the entry role - if _, e := template.New("name").Funcs(tplFuncMap).Parse(role.Name); e != nil { + if e := utils.ValidateTokenNameName(role); e != nil { err = multierror.Append(err, fmt.Errorf("invalid template %s for name: %w", role.Name, e)) } diff --git a/path_token_role.go b/path_token_role.go index 42ca317..0618db0 100644 --- a/path_token_role.go +++ b/path_token_role.go @@ -65,7 +65,7 @@ func (b *Backend) pathTokenRoleCreate(ctx context.Context, req *logical.Request, var expiresAt time.Time var startTime = TimeFromContext(ctx).UTC() - name, err = TokenName(role) + name, err = utils.TokenName(role) if err != nil { return nil, fmt.Errorf("error generating token name: %w", err) } From 691c2e17a53524c909dbe966b6d767426dcc3e5a Mon Sep 17 00:00:00 2001 From: Ilija Matoski Date: Tue, 12 Aug 2025 09:42:31 +0200 Subject: [PATCH 14/17] move some app ctx helpers --- backend.go | 3 ++- defs.go | 25 ------------------- defs_test.go | 3 ++- gitlab_client.go | 2 +- go.sum | 2 -- helpers_test.go | 7 +++--- internal/utils/ctx.go | 3 +++ internal/utils/ctx_http_client.go | 22 ++++++++++++++++ internal/utils/ctx_time.go | 22 ++++++++++++++++ path_config.go | 3 ++- path_config_test.go | 13 +++++----- path_token_role.go | 2 +- path_token_role_multiple_config_test.go | 3 ++- secret_access_tokens_test.go | 3 ++- ...dmin_user_pat_gitlab_revokes_token_test.go | 3 ++- ...admin_user_pat_vault_revokes_token_test.go | 3 ++- with_gitlab_com_user_rotate_token_test.go | 3 ++- with_group_deploy_token_test.go | 3 ++- with_normal_user_gat_test.go | 3 ++- with_normal_user_personal_at_fails_test.go | 3 ++- with_normal_user_project_at_test.go | 3 ++- with_pipeline_project_trigger_token_test.go | 3 ++- with_project_deploy_token_test.go | 3 ++- with_service_account_fail_test.go | 3 ++- with_service_account_group_test.go | 3 ++- with_service_account_user_test.go | 3 ++- 26 files changed, 94 insertions(+), 55 deletions(-) create mode 100644 internal/utils/ctx.go create mode 100644 internal/utils/ctx_http_client.go create mode 100644 internal/utils/ctx_time.go diff --git a/backend.go b/backend.go index df5a069..6e1ac52 100644 --- a/backend.go +++ b/backend.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/vault/sdk/logical" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/flags" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) const ( @@ -182,7 +183,7 @@ func (b *Backend) getClient(ctx context.Context, s logical.Storage, name string) } var httpClient *http.Client - httpClient, _ = HttpClientFromContext(ctx) + httpClient, _ = utils.HttpClientFromContext(ctx) if client, _ = ClientFromContext(ctx); client == nil { if client, err = NewGitlabClient(config, httpClient, b.Logger()); err == nil { b.SetClient(client, name) diff --git a/defs.go b/defs.go index 0aeb2f6..3aa1606 100644 --- a/defs.go +++ b/defs.go @@ -2,7 +2,6 @@ package gitlab import ( "context" - "net/http" "time" ) @@ -22,30 +21,6 @@ const ( DefaultConfigName = "default" ) -func WithStaticTime(ctx context.Context, t time.Time) context.Context { - return context.WithValue(ctx, ctxKeyTimeNow, t) -} - -func TimeFromContext(ctx context.Context) time.Time { - t, ok := ctx.Value(ctxKeyTimeNow).(time.Time) - if !ok { - return time.Now() - } - return t -} - -func HttpClientNewContext(ctx context.Context, httpClient *http.Client) context.Context { - return context.WithValue(ctx, ctxKeyHttpClient, httpClient) -} - -func HttpClientFromContext(ctx context.Context) (*http.Client, bool) { - u, ok := ctx.Value(ctxKeyHttpClient).(*http.Client) - if !ok { - u = nil - } - return u, ok -} - func ClientNewContext(ctx context.Context, client Client) context.Context { return context.WithValue(ctx, ctxKeyGitlabClient, client) } diff --git a/defs_test.go b/defs_test.go index dfcd3ef..1da1e7e 100644 --- a/defs_test.go +++ b/defs_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/require" gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) func TestEmptyGitlabClientFromContext(t *testing.T) { @@ -17,7 +18,7 @@ func TestEmptyGitlabClientFromContext(t *testing.T) { } func TestEmptyHttpClientFromContext(t *testing.T) { - c, ok := gitlab.HttpClientFromContext(t.Context()) + c, ok := utils.HttpClientFromContext(t.Context()) require.False(t, ok) require.Nil(t, c) } diff --git a/gitlab_client.go b/gitlab_client.go index ab676fa..42b895b 100644 --- a/gitlab_client.go +++ b/gitlab_client.go @@ -371,7 +371,7 @@ func (gc *gitlabClient) RotateCurrentToken(ctx context.Context) (token *models.T var pat *g.PersonalAccessToken var durationTTL = currentEntryToken.ExpiresAt.Sub(*currentEntryToken.CreatedAt) - _, expiresAt, _ = utils.CalculateGitlabTTL(durationTTL, TimeFromContext(ctx)) + _, expiresAt, _ = utils.CalculateGitlabTTL(durationTTL, utils.TimeFromContext(ctx)) pat, _, err = gc.client.PersonalAccessTokens.RotatePersonalAccessToken( currentEntryToken.TokenID, &g.RotatePersonalAccessTokenOptions{ExpiresAt: (*g.ISOTime)(&expiresAt)}, diff --git a/go.sum b/go.sum index 01ae9c8..be62d2d 100644 --- a/go.sum +++ b/go.sum @@ -626,8 +626,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/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= -gopkg.in/dnaeon/go-vcr.v4 v4.0.2 h1:7T5VYf2ifyK01ETHbJPl5A6XTpUljD4Trw3GEDcdedk= -gopkg.in/dnaeon/go-vcr.v4 v4.0.2/go.mod h1:65yxh9goQVrudqofKtHA4JNFWd6XZRkWfKN4YpMx7KI= gopkg.in/dnaeon/go-vcr.v4 v4.0.3 h1:rlSB7VRNGo90rqbNWA3+/3iftkjLEvcf3bhkAULqE0o= gopkg.in/dnaeon/go-vcr.v4 v4.0.3/go.mod h1:65yxh9goQVrudqofKtHA4JNFWd6XZRkWfKN4YpMx7KI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= diff --git a/helpers_test.go b/helpers_test.go index 27c6224..f093a4d 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -30,6 +30,7 @@ import ( "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/flags" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/models" t "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) var _ gitlab.Client = new(inMemoryClient) @@ -579,12 +580,12 @@ func sanitizePath(path string) string { func getCtxGitlabClient(t *testing.T, target string) context.Context { httpClient, _ := getClient(t, target) - return gitlab.HttpClientNewContext(t.Context(), httpClient) + return utils.HttpClientNewContext(t.Context(), httpClient) } func getCtxGitlabClientWithUrl(t *testing.T, target string) (context.Context, string) { httpClient, url := getClient(t, target) - return gitlab.HttpClientNewContext(t.Context(), httpClient), url + return utils.HttpClientNewContext(t.Context(), httpClient), url } func parseTimeFromFile(name string) (t time.Time, err error) { @@ -619,7 +620,7 @@ func ctxTestTime(ctx context.Context, testName string, tokenName string) (_ cont } else { t = token.CreatedAtTime() } - return gitlab.WithStaticTime(ctx, t), t + return utils.WithStaticTime(ctx, t), t } func filterSlice[T any, Slice ~[]T](collection Slice, predicate func(item T, index int) bool) Slice { diff --git a/internal/utils/ctx.go b/internal/utils/ctx.go new file mode 100644 index 0000000..f9ef064 --- /dev/null +++ b/internal/utils/ctx.go @@ -0,0 +1,3 @@ +package utils + +type contextKey string diff --git a/internal/utils/ctx_http_client.go b/internal/utils/ctx_http_client.go new file mode 100644 index 0000000..e51f453 --- /dev/null +++ b/internal/utils/ctx_http_client.go @@ -0,0 +1,22 @@ +package utils + +import ( + "context" + "net/http" +) + +var ( + ctxKeyHttpClient = contextKey("vpsg-ctx-key-http-client") +) + +func HttpClientNewContext(ctx context.Context, httpClient *http.Client) context.Context { + return context.WithValue(ctx, ctxKeyHttpClient, httpClient) +} + +func HttpClientFromContext(ctx context.Context) (*http.Client, bool) { + u, ok := ctx.Value(ctxKeyHttpClient).(*http.Client) + if !ok { + u = nil + } + return u, ok +} diff --git a/internal/utils/ctx_time.go b/internal/utils/ctx_time.go new file mode 100644 index 0000000..79baf96 --- /dev/null +++ b/internal/utils/ctx_time.go @@ -0,0 +1,22 @@ +package utils + +import ( + "context" + "time" +) + +var ( + ctxKeyTimeNow = contextKey("vpsg-ctx-key-time-now") +) + +func WithStaticTime(ctx context.Context, t time.Time) context.Context { + return context.WithValue(ctx, ctxKeyTimeNow, t) +} + +func TimeFromContext(ctx context.Context) time.Time { + t, ok := ctx.Value(ctxKeyTimeNow).(time.Time) + if !ok { + return time.Now() + } + return t +} diff --git a/path_config.go b/path_config.go index 2d2fe54..0877c0b 100644 --- a/path_config.go +++ b/path_config.go @@ -16,6 +16,7 @@ import ( "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/event" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/models" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) const ( @@ -160,7 +161,7 @@ func (b *Backend) pathConfigPatch(ctx context.Context, req *logical.Request, dat func (b *Backend) updateConfigClientInfo(ctx context.Context, config *EntryConfig) (et *models.TokenConfig, err error) { var httpClient *http.Client var client Client - httpClient, _ = HttpClientFromContext(ctx) + httpClient, _ = utils.HttpClientFromContext(ctx) if client, _ = ClientFromContext(ctx); client == nil { if client, err = NewGitlabClient(config, httpClient, b.Logger()); err == nil { b.SetClient(client, config.Name) diff --git a/path_config_test.go b/path_config_test.go index 07494fc..266138d 100644 --- a/path_config_test.go +++ b/path_config_test.go @@ -15,6 +15,7 @@ import ( "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/flags" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) func TestPathConfig(t *testing.T) { @@ -50,7 +51,7 @@ func TestPathConfig(t *testing.T) { t.Run("write, read, delete and read config", func(t *testing.T) { httpClient, url := getClient(t, "unit") - ctx := gitlab.HttpClientNewContext(t.Context(), httpClient) + ctx := utils.HttpClientNewContext(t.Context(), httpClient) b, l, events, err := getBackendWithEvents(ctx) require.NoError(t, err) @@ -106,7 +107,7 @@ func TestPathConfig(t *testing.T) { t.Run("write, read, delete and read config with show config token", func(t *testing.T) { httpClient, url := getClient(t, "unit") - ctx := gitlab.HttpClientNewContext(t.Context(), httpClient) + ctx := utils.HttpClientNewContext(t.Context(), httpClient) b, l, events, err := getBackendWithFlagsWithEvents(ctx, flags.Flags{ShowConfigToken: true}) require.NoError(t, err) @@ -161,7 +162,7 @@ func TestPathConfig(t *testing.T) { }) t.Run("invalid token", func(t *testing.T) { httpClient, url := getClient(t, "unit") - ctx := gitlab.HttpClientNewContext(t.Context(), httpClient) + ctx := utils.HttpClientNewContext(t.Context(), httpClient) b, l, events, err := getBackendWithEvents(ctx) require.NoError(t, err) @@ -203,7 +204,7 @@ func TestPathConfig(t *testing.T) { t.Run("patch a config with no storage", func(t *testing.T) { httpClient, url := getClient(t, "unit") - ctx := gitlab.HttpClientNewContext(t.Context(), httpClient) + ctx := utils.HttpClientNewContext(t.Context(), httpClient) b, _, err := getBackend(ctx) require.NoError(t, err) @@ -224,7 +225,7 @@ func TestPathConfig(t *testing.T) { t.Run("patch a config no backend", func(t *testing.T) { httpClient, url := getClient(t, "unit") - ctx := gitlab.HttpClientNewContext(t.Context(), httpClient) + ctx := utils.HttpClientNewContext(t.Context(), httpClient) b, l, err := getBackend(ctx) require.NoError(t, err) @@ -246,7 +247,7 @@ func TestPathConfig(t *testing.T) { t.Run("patch a config", func(t *testing.T) { httpClient, url := getClient(t, "unit") - ctx := gitlab.HttpClientNewContext(t.Context(), httpClient) + ctx := utils.HttpClientNewContext(t.Context(), httpClient) var path = fmt.Sprintf("%s/%s", gitlab.PathConfigStorage, gitlab.DefaultConfigName) b, l, events, err := getBackendWithEvents(ctx) diff --git a/path_token_role.go b/path_token_role.go index 0618db0..0a357f7 100644 --- a/path_token_role.go +++ b/path_token_role.go @@ -63,7 +63,7 @@ func (b *Backend) pathTokenRoleCreate(ctx context.Context, req *logical.Request, var name string var token token2.Token var expiresAt time.Time - var startTime = TimeFromContext(ctx).UTC() + var startTime = utils.TimeFromContext(ctx).UTC() name, err = utils.TokenName(role) if err != nil { diff --git a/path_token_role_multiple_config_test.go b/path_token_role_multiple_config_test.go index d775021..9261847 100644 --- a/path_token_role_multiple_config_test.go +++ b/path_token_role_multiple_config_test.go @@ -13,11 +13,12 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) func TestPathTokenRolesMultipleConfigs(t *testing.T) { httpClient, gitlabUrl := getClient(t, "unit") - ctx := gitlab.HttpClientNewContext(t.Context(), httpClient) + ctx := utils.HttpClientNewContext(t.Context(), httpClient) b, l, events, err := getBackendWithEvents(ctx) require.NoError(t, err) diff --git a/secret_access_tokens_test.go b/secret_access_tokens_test.go index 311095e..4b941fb 100644 --- a/secret_access_tokens_test.go +++ b/secret_access_tokens_test.go @@ -12,11 +12,12 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) func TestSecretAccessTokenRevokeToken(t *testing.T) { httpClient, url := getClient(t, "unit") - ctx := gitlab.HttpClientNewContext(t.Context(), httpClient) + ctx := utils.HttpClientNewContext(t.Context(), httpClient) b, l, events, err := getBackendWithEvents(ctx) require.NoError(t, err) diff --git a/with_admin_user_pat_gitlab_revokes_token_test.go b/with_admin_user_pat_gitlab_revokes_token_test.go index 1cd5dfe..65ef125 100644 --- a/with_admin_user_pat_gitlab_revokes_token_test.go +++ b/with_admin_user_pat_gitlab_revokes_token_test.go @@ -17,11 +17,12 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" token2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) func TestWithAdminUser_PAT_AdminUser_GitlabRevokesToken(t *testing.T) { httpClient, url := getClient(t, "local") - ctx := gitlab.HttpClientNewContext(t.Context(), httpClient) + ctx := utils.HttpClientNewContext(t.Context(), httpClient) b, l, events, err := getBackendWithEvents(ctx) require.NoError(t, err) diff --git a/with_admin_user_pat_vault_revokes_token_test.go b/with_admin_user_pat_vault_revokes_token_test.go index 4cc24e1..a4c7caa 100644 --- a/with_admin_user_pat_vault_revokes_token_test.go +++ b/with_admin_user_pat_vault_revokes_token_test.go @@ -17,11 +17,12 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" token2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) func TestWithAdminUser_PAT_AdminUser_VaultRevokesToken(t *testing.T) { httpClient, url := getClient(t, "local") - ctx := gitlab.HttpClientNewContext(t.Context(), httpClient) + ctx := utils.HttpClientNewContext(t.Context(), httpClient) var tokenName = "admin_user_initial_token" b, l, events, err := getBackendWithEvents(ctx) diff --git a/with_gitlab_com_user_rotate_token_test.go b/with_gitlab_com_user_rotate_token_test.go index 2fc2216..ac29ae0 100644 --- a/with_gitlab_com_user_rotate_token_test.go +++ b/with_gitlab_com_user_rotate_token_test.go @@ -13,11 +13,12 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) func TestWithGitlabUser_RotateToken(t *testing.T) { httpClient, _ := getClient(t, "saas") - ctx := gitlab.HttpClientNewContext(t.Context(), httpClient) + ctx := utils.HttpClientNewContext(t.Context(), httpClient) var tokenName = "" b, l, events, err := getBackendWithEvents(ctx) diff --git a/with_group_deploy_token_test.go b/with_group_deploy_token_test.go index 1deff0b..b906be5 100644 --- a/with_group_deploy_token_test.go +++ b/with_group_deploy_token_test.go @@ -15,11 +15,12 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" token2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) func TestWithGroupDeployToken(t *testing.T) { httpClient, url := getClient(t, "local") - ctx := gitlab.HttpClientNewContext(t.Context(), httpClient) + ctx := utils.HttpClientNewContext(t.Context(), httpClient) var tokenName = "normal_user_initial_token" b, l, events, err := getBackendWithEvents(ctx) diff --git a/with_normal_user_gat_test.go b/with_normal_user_gat_test.go index 55e8d9f..c60d58c 100644 --- a/with_normal_user_gat_test.go +++ b/with_normal_user_gat_test.go @@ -17,11 +17,12 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" token2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) func TestWithNormalUser_GAT(t *testing.T) { httpClient, url := getClient(t, "local") - ctx := gitlab.HttpClientNewContext(t.Context(), httpClient) + ctx := utils.HttpClientNewContext(t.Context(), httpClient) var tokenName = "normal_user_initial_token" b, l, events, err := getBackendWithEvents(ctx) diff --git a/with_normal_user_personal_at_fails_test.go b/with_normal_user_personal_at_fails_test.go index cfbd1d8..f79edea 100644 --- a/with_normal_user_personal_at_fails_test.go +++ b/with_normal_user_personal_at_fails_test.go @@ -15,11 +15,12 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) func TestWithNormalUser_PersonalAT_Fails(t *testing.T) { httpClient, url := getClient(t, "local") - ctx := gitlab.HttpClientNewContext(t.Context(), httpClient) + ctx := utils.HttpClientNewContext(t.Context(), httpClient) var tokenName = "normal_user_initial_token" b, l, events, err := getBackendWithEvents(ctx) diff --git a/with_normal_user_project_at_test.go b/with_normal_user_project_at_test.go index ab89cce..336a1e2 100644 --- a/with_normal_user_project_at_test.go +++ b/with_normal_user_project_at_test.go @@ -17,11 +17,12 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" tok "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) func TestWithNormalUser_ProjectAT(t *testing.T) { httpClient, url := getClient(t, "local") - ctx := gitlab.HttpClientNewContext(t.Context(), httpClient) + ctx := utils.HttpClientNewContext(t.Context(), httpClient) var tokenName = "normal_user_initial_token" b, l, events, err := getBackendWithEvents(ctx) diff --git a/with_pipeline_project_trigger_token_test.go b/with_pipeline_project_trigger_token_test.go index f65cd59..544197c 100644 --- a/with_pipeline_project_trigger_token_test.go +++ b/with_pipeline_project_trigger_token_test.go @@ -14,11 +14,12 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" token2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) func TestWithPipelineProjectTriggerAccessToken(t *testing.T) { httpClient, url := getClient(t, "local") - ctx := gitlab.HttpClientNewContext(t.Context(), httpClient) + ctx := utils.HttpClientNewContext(t.Context(), httpClient) var tokenName = "normal_user_initial_token" b, l, events, err := getBackendWithEvents(ctx) diff --git a/with_project_deploy_token_test.go b/with_project_deploy_token_test.go index a9d79fa..5ec5358 100644 --- a/with_project_deploy_token_test.go +++ b/with_project_deploy_token_test.go @@ -15,11 +15,12 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" token2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) func TestWithProjectDeployToken(t *testing.T) { httpClient, url := getClient(t, "local") - ctx := gitlab.HttpClientNewContext(t.Context(), httpClient) + ctx := utils.HttpClientNewContext(t.Context(), httpClient) var tokenName = "normal_user_initial_token" b, l, events, err := getBackendWithEvents(ctx) diff --git a/with_service_account_fail_test.go b/with_service_account_fail_test.go index 37246b0..60834f6 100644 --- a/with_service_account_fail_test.go +++ b/with_service_account_fail_test.go @@ -13,6 +13,7 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) func TestWithServiceAccountUserFail(t *testing.T) { @@ -22,7 +23,7 @@ func TestWithServiceAccountUserFail(t *testing.T) { } { t.Run(typ.String(), func(t *testing.T) { httpClient, _ := getClient(t, "selfhosted") - ctx := gitlab.HttpClientNewContext(t.Context(), httpClient) + ctx := utils.HttpClientNewContext(t.Context(), httpClient) b, l, events, err := getBackendWithEvents(ctx) require.NoError(t, err) diff --git a/with_service_account_group_test.go b/with_service_account_group_test.go index c50059a..a2b1523 100644 --- a/with_service_account_group_test.go +++ b/with_service_account_group_test.go @@ -15,11 +15,12 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" token2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) func TestWithServiceAccountGroup(t *testing.T) { httpClient, _ := getClient(t, "selfhosted") - ctx := gitlab.HttpClientNewContext(t.Context(), httpClient) + ctx := utils.HttpClientNewContext(t.Context(), httpClient) var tokenName = "" b, l, events, err := getBackendWithEvents(ctx) diff --git a/with_service_account_user_test.go b/with_service_account_user_test.go index d066b24..90fbfb1 100644 --- a/with_service_account_user_test.go +++ b/with_service_account_user_test.go @@ -14,11 +14,12 @@ import ( gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" gitlab2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" token2 "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) func TestWithServiceAccountUser(t *testing.T) { httpClient, _ := getClient(t, "selfhosted") - ctx := gitlab.HttpClientNewContext(t.Context(), httpClient) + ctx := utils.HttpClientNewContext(t.Context(), httpClient) var tokenName = "" b, l, events, err := getBackendWithEvents(ctx) From 7df07336465907585745560f953db6ba04baddb0 Mon Sep 17 00:00:00 2001 From: Ilija Matoski Date: Tue, 12 Aug 2025 10:05:01 +0200 Subject: [PATCH 15/17] move client and add tests for ctx --- backend.go | 3 +- defs.go | 18 ------------ defs_test.go | 24 ---------------- internal/gitlab/client.go | 38 ++++++++++++++++++++++++++ internal/gitlab/ctx.go | 21 ++++++++++++++ internal/gitlab/ctx_test.go | 15 ++++++++++ internal/utils/ctx_http_client_test.go | 25 +++++++++++++++++ internal/utils/ctx_time_test.go | 24 ++++++++++++++++ path_config.go | 2 +- path_config_token_autorotate_test.go | 6 ++-- path_token_role_test.go | 2 +- 11 files changed, 130 insertions(+), 48 deletions(-) delete mode 100644 defs_test.go create mode 100644 internal/gitlab/client.go create mode 100644 internal/gitlab/ctx.go create mode 100644 internal/gitlab/ctx_test.go create mode 100644 internal/utils/ctx_http_client_test.go create mode 100644 internal/utils/ctx_time_test.go diff --git a/backend.go b/backend.go index 6e1ac52..d15f5e2 100644 --- a/backend.go +++ b/backend.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/vault/sdk/logical" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/flags" + g "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" ) @@ -184,7 +185,7 @@ func (b *Backend) getClient(ctx context.Context, s logical.Storage, name string) var httpClient *http.Client httpClient, _ = utils.HttpClientFromContext(ctx) - if client, _ = ClientFromContext(ctx); client == nil { + if client, _ = g.ClientFromContext(ctx); client == nil { if client, err = NewGitlabClient(config, httpClient, b.Logger()); err == nil { b.SetClient(client, name) } diff --git a/defs.go b/defs.go index 3aa1606..f2d116f 100644 --- a/defs.go +++ b/defs.go @@ -1,12 +1,9 @@ package gitlab import ( - "context" "time" ) -type contextKey string - const ( DefaultConfigFieldAccessTokenMaxTTL = 7 * 24 * time.Hour DefaultConfigFieldAccessTokenRotate = DefaultAutoRotateBeforeMinTTL @@ -15,20 +12,5 @@ const ( DefaultAccessTokenMaxPossibleTTL = 365 * 24 * time.Hour DefaultAutoRotateBeforeMinTTL = 24 * time.Hour DefaultAutoRotateBeforeMaxTTL = 730 * time.Hour - ctxKeyHttpClient = contextKey("vpsg-ctx-key-http-client") - ctxKeyGitlabClient = contextKey("vpsg-ctx-key-gitlab-client") - ctxKeyTimeNow = contextKey("vpsg-ctx-key-time-now") DefaultConfigName = "default" ) - -func ClientNewContext(ctx context.Context, client Client) context.Context { - return context.WithValue(ctx, ctxKeyGitlabClient, client) -} - -func ClientFromContext(ctx context.Context) (Client, bool) { - u, ok := ctx.Value(ctxKeyGitlabClient).(Client) - if !ok { - u = nil - } - return u, ok -} diff --git a/defs_test.go b/defs_test.go deleted file mode 100644 index 1da1e7e..0000000 --- a/defs_test.go +++ /dev/null @@ -1,24 +0,0 @@ -//go:build unit - -package gitlab_test - -import ( - "testing" - - "github.com/stretchr/testify/require" - - gitlab "github.com/ilijamt/vault-plugin-secrets-gitlab" - "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" -) - -func TestEmptyGitlabClientFromContext(t *testing.T) { - c, ok := gitlab.ClientFromContext(t.Context()) - require.False(t, ok) - require.Nil(t, c) -} - -func TestEmptyHttpClientFromContext(t *testing.T) { - c, ok := utils.HttpClientFromContext(t.Context()) - require.False(t, ok) - require.Nil(t, c) -} diff --git a/internal/gitlab/client.go b/internal/gitlab/client.go new file mode 100644 index 0000000..76adf0e --- /dev/null +++ b/internal/gitlab/client.go @@ -0,0 +1,38 @@ +package gitlab + +import ( + "context" + "time" + + g "gitlab.com/gitlab-org/api/client-go" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/models" + t "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" +) + +type Client interface { + GitlabClient(ctx context.Context) *g.Client + Valid(ctx context.Context) bool + Metadata(ctx context.Context) (*g.Metadata, error) + CurrentTokenInfo(ctx context.Context) (*models.TokenConfig, error) + RotateCurrentToken(ctx context.Context) (newToken *models.TokenConfig, oldToken *models.TokenConfig, err error) + CreatePersonalAccessToken(ctx context.Context, username string, userId int, name string, expiresAt time.Time, scopes []string) (*models.TokenPersonal, error) + CreateGroupAccessToken(ctx context.Context, groupId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (*models.TokenGroup, error) + CreateProjectAccessToken(ctx context.Context, projectId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (*models.TokenProject, error) + RevokePersonalAccessToken(ctx context.Context, tokenId int) error + RevokeProjectAccessToken(ctx context.Context, tokenId int, projectId string) error + RevokeGroupAccessToken(ctx context.Context, tokenId int, groupId string) error + GetUserIdByUsername(ctx context.Context, username string) (int, error) + GetGroupIdByPath(ctx context.Context, path string) (int, error) + GetProjectIdByPath(ctx context.Context, path string) (int, error) + CreateGroupServiceAccountAccessToken(ctx context.Context, group string, groupId string, userId int, name string, expiresAt time.Time, scopes []string) (*models.TokenGroupServiceAccount, error) + CreateUserServiceAccountAccessToken(ctx context.Context, username string, userId int, name string, expiresAt time.Time, scopes []string) (*models.TokenUserServiceAccount, error) + RevokeUserServiceAccountAccessToken(ctx context.Context, token string) error + RevokeGroupServiceAccountAccessToken(ctx context.Context, token string) error + CreatePipelineProjectTriggerAccessToken(ctx context.Context, path, name string, projectId int, description string, expiresAt *time.Time) (*models.TokenPipelineProjectTrigger, error) + RevokePipelineProjectTriggerAccessToken(ctx context.Context, projectId int, tokenId int) error + CreateProjectDeployToken(ctx context.Context, path string, projectId int, name string, expiresAt *time.Time, scopes []string) (et *models.TokenProjectDeploy, err error) + RevokeProjectDeployToken(ctx context.Context, projectId, deployTokenId int) (err error) + CreateGroupDeployToken(ctx context.Context, path string, groupId int, name string, expiresAt *time.Time, scopes []string) (et *models.TokenGroupDeploy, err error) + RevokeGroupDeployToken(ctx context.Context, groupId, deployTokenId int) (err error) +} diff --git a/internal/gitlab/ctx.go b/internal/gitlab/ctx.go new file mode 100644 index 0000000..4452cc6 --- /dev/null +++ b/internal/gitlab/ctx.go @@ -0,0 +1,21 @@ +package gitlab + +import "context" + +type contextKey string + +var ( + ctxKeyGitlabClient = contextKey("vpsg-ctx-key-gitlab-client") +) + +func ClientNewContext(ctx context.Context, client Client) context.Context { + return context.WithValue(ctx, ctxKeyGitlabClient, client) +} + +func ClientFromContext(ctx context.Context) (Client, bool) { + u, ok := ctx.Value(ctxKeyGitlabClient).(Client) + if !ok { + u = nil + } + return u, ok +} diff --git a/internal/gitlab/ctx_test.go b/internal/gitlab/ctx_test.go new file mode 100644 index 0000000..0187d97 --- /dev/null +++ b/internal/gitlab/ctx_test.go @@ -0,0 +1,15 @@ +package gitlab_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/gitlab" +) + +func TestEmptyGitlabClientFromContext(t *testing.T) { + c, ok := gitlab.ClientFromContext(t.Context()) + require.False(t, ok) + require.Nil(t, c) +} diff --git a/internal/utils/ctx_http_client_test.go b/internal/utils/ctx_http_client_test.go new file mode 100644 index 0000000..456d56d --- /dev/null +++ b/internal/utils/ctx_http_client_test.go @@ -0,0 +1,25 @@ +package utils_test + +import ( + "net/http" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" +) + +func TestHttpClientFromContext(t *testing.T) { + t.Run("no http client", func(t *testing.T) { + c, ok := utils.HttpClientFromContext(t.Context()) + require.False(t, ok) + require.Nil(t, c) + }) + + t.Run("with http client", func(t *testing.T) { + ctx := utils.HttpClientNewContext(t.Context(), &http.Client{}) + c, ok := utils.HttpClientFromContext(ctx) + require.True(t, ok) + require.NotNil(t, c) + }) +} diff --git a/internal/utils/ctx_time_test.go b/internal/utils/ctx_time_test.go new file mode 100644 index 0000000..1695540 --- /dev/null +++ b/internal/utils/ctx_time_test.go @@ -0,0 +1,24 @@ +package utils_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/utils" +) + +func TestWithTime(t *testing.T) { + t.Run("no time should default to time now", func(t *testing.T) { + tm := utils.TimeFromContext(t.Context()) + require.False(t, tm.IsZero()) + }) + + t.Run("with time", func(t *testing.T) { + tm := time.Date(2009, 1, 1, 1, 0, 0, 0, time.UTC) + ctx := utils.WithStaticTime(t.Context(), tm) + tmCtx := utils.TimeFromContext(ctx) + require.False(t, tmCtx.IsZero()) + }) +} diff --git a/path_config.go b/path_config.go index 0877c0b..ba359bd 100644 --- a/path_config.go +++ b/path_config.go @@ -162,7 +162,7 @@ func (b *Backend) updateConfigClientInfo(ctx context.Context, config *EntryConfi var httpClient *http.Client var client Client httpClient, _ = utils.HttpClientFromContext(ctx) - if client, _ = ClientFromContext(ctx); client == nil { + if client, _ = gitlab.ClientFromContext(ctx); client == nil { if client, err = NewGitlabClient(config, httpClient, b.Logger()); err == nil { b.SetClient(client, config.Name) } else { diff --git a/path_config_token_autorotate_test.go b/path_config_token_autorotate_test.go index 4534a2e..836b226 100644 --- a/path_config_token_autorotate_test.go +++ b/path_config_token_autorotate_test.go @@ -159,7 +159,7 @@ func TestPathConfig_AutoRotateToken(t *testing.T) { t.Run("no error when auto rotate is disabled and config is set", func(t *testing.T) { var client = newInMemoryClient(true) ctx, url := getCtxGitlabClientWithUrl(t, "unit") - ctx = gitlab.ClientNewContext(ctx, client) + ctx = gitlab2.ClientNewContext(ctx, client) b, l, err := getBackendWithConfig(ctx, map[string]any{ "token": "glpat-secret-token", "base_url": url, @@ -175,7 +175,7 @@ func TestPathConfig_AutoRotateToken(t *testing.T) { t.Run("call auto rotate the main token and rotate the token", func(t *testing.T) { var client = newInMemoryClient(true) ctx, url := getCtxGitlabClientWithUrl(t, "unit") - ctx = gitlab.ClientNewContext(ctx, newInMemoryClient(true)) + ctx = gitlab2.ClientNewContext(ctx, newInMemoryClient(true)) b, l, events, err := getBackendWithEventsAndConfig(ctx, map[string]any{ "token": "token", "base_url": url, @@ -226,7 +226,7 @@ func TestPathConfig_AutoRotateToken(t *testing.T) { t.Run("call auto rotate the main token but the token is still valid", func(t *testing.T) { var client = newInMemoryClient(true) ctx, url := getCtxGitlabClientWithUrl(t, "unit") - ctx = gitlab.ClientNewContext(ctx, newInMemoryClient(true)) + ctx = gitlab2.ClientNewContext(ctx, newInMemoryClient(true)) b, l, err := getBackendWithConfig(ctx, map[string]any{ "token": "token", "base_url": url, diff --git a/path_token_role_test.go b/path_token_role_test.go index 0f043e4..b605edc 100644 --- a/path_token_role_test.go +++ b/path_token_role_test.go @@ -41,7 +41,7 @@ func TestPathTokenRoles(t *testing.T) { t.Logf("token creation, token type: %s, level: %s, gitlab revokes token: %t", tokenType, level, gitlabRevokesToken) ctx := getCtxGitlabClient(t, "unit") client := newInMemoryClient(true) - ctx = gitlab.ClientNewContext(ctx, client) + ctx = gitlab2.ClientNewContext(ctx, client) var b, l, events, err = getBackendWithEvents(ctx) require.NoError(t, err) require.NoError(t, writeBackendConfig(ctx, b, l, defaultConfig)) From d767254620abf8cc1da86f1af08bba867a167678 Mon Sep 17 00:00:00 2001 From: Ilija Matoski Date: Tue, 12 Aug 2025 10:08:20 +0200 Subject: [PATCH 16/17] separate iface --- gitlab_client.go | 27 --------------------------- gitlab_client_iface.go | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 27 deletions(-) create mode 100644 gitlab_client_iface.go diff --git a/gitlab_client.go b/gitlab_client.go index 42b895b..913295a 100644 --- a/gitlab_client.go +++ b/gitlab_client.go @@ -26,33 +26,6 @@ var ( ErrRoleNotFound = errors.New("role not found") ) -type Client interface { - GitlabClient(ctx context.Context) *g.Client - Valid(ctx context.Context) bool - Metadata(ctx context.Context) (*g.Metadata, error) - CurrentTokenInfo(ctx context.Context) (*models.TokenConfig, error) - RotateCurrentToken(ctx context.Context) (newToken *models.TokenConfig, oldToken *models.TokenConfig, err error) - CreatePersonalAccessToken(ctx context.Context, username string, userId int, name string, expiresAt time.Time, scopes []string) (*models.TokenPersonal, error) - CreateGroupAccessToken(ctx context.Context, groupId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (*models.TokenGroup, error) - CreateProjectAccessToken(ctx context.Context, projectId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (*models.TokenProject, error) - RevokePersonalAccessToken(ctx context.Context, tokenId int) error - RevokeProjectAccessToken(ctx context.Context, tokenId int, projectId string) error - RevokeGroupAccessToken(ctx context.Context, tokenId int, groupId string) error - GetUserIdByUsername(ctx context.Context, username string) (int, error) - GetGroupIdByPath(ctx context.Context, path string) (int, error) - GetProjectIdByPath(ctx context.Context, path string) (int, error) - CreateGroupServiceAccountAccessToken(ctx context.Context, group string, groupId string, userId int, name string, expiresAt time.Time, scopes []string) (*models.TokenGroupServiceAccount, error) - CreateUserServiceAccountAccessToken(ctx context.Context, username string, userId int, name string, expiresAt time.Time, scopes []string) (*models.TokenUserServiceAccount, error) - RevokeUserServiceAccountAccessToken(ctx context.Context, token string) error - RevokeGroupServiceAccountAccessToken(ctx context.Context, token string) error - CreatePipelineProjectTriggerAccessToken(ctx context.Context, path, name string, projectId int, description string, expiresAt *time.Time) (*models.TokenPipelineProjectTrigger, error) - RevokePipelineProjectTriggerAccessToken(ctx context.Context, projectId int, tokenId int) error - CreateProjectDeployToken(ctx context.Context, path string, projectId int, name string, expiresAt *time.Time, scopes []string) (et *models.TokenProjectDeploy, err error) - RevokeProjectDeployToken(ctx context.Context, projectId, deployTokenId int) (err error) - CreateGroupDeployToken(ctx context.Context, path string, groupId int, name string, expiresAt *time.Time, scopes []string) (et *models.TokenGroupDeploy, err error) - RevokeGroupDeployToken(ctx context.Context, groupId, deployTokenId int) (err error) -} - type gitlabClient struct { client *g.Client httpClient *http.Client diff --git a/gitlab_client_iface.go b/gitlab_client_iface.go new file mode 100644 index 0000000..76adf0e --- /dev/null +++ b/gitlab_client_iface.go @@ -0,0 +1,38 @@ +package gitlab + +import ( + "context" + "time" + + g "gitlab.com/gitlab-org/api/client-go" + + "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/models" + t "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token" +) + +type Client interface { + GitlabClient(ctx context.Context) *g.Client + Valid(ctx context.Context) bool + Metadata(ctx context.Context) (*g.Metadata, error) + CurrentTokenInfo(ctx context.Context) (*models.TokenConfig, error) + RotateCurrentToken(ctx context.Context) (newToken *models.TokenConfig, oldToken *models.TokenConfig, err error) + CreatePersonalAccessToken(ctx context.Context, username string, userId int, name string, expiresAt time.Time, scopes []string) (*models.TokenPersonal, error) + CreateGroupAccessToken(ctx context.Context, groupId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (*models.TokenGroup, error) + CreateProjectAccessToken(ctx context.Context, projectId string, name string, expiresAt time.Time, scopes []string, accessLevel t.AccessLevel) (*models.TokenProject, error) + RevokePersonalAccessToken(ctx context.Context, tokenId int) error + RevokeProjectAccessToken(ctx context.Context, tokenId int, projectId string) error + RevokeGroupAccessToken(ctx context.Context, tokenId int, groupId string) error + GetUserIdByUsername(ctx context.Context, username string) (int, error) + GetGroupIdByPath(ctx context.Context, path string) (int, error) + GetProjectIdByPath(ctx context.Context, path string) (int, error) + CreateGroupServiceAccountAccessToken(ctx context.Context, group string, groupId string, userId int, name string, expiresAt time.Time, scopes []string) (*models.TokenGroupServiceAccount, error) + CreateUserServiceAccountAccessToken(ctx context.Context, username string, userId int, name string, expiresAt time.Time, scopes []string) (*models.TokenUserServiceAccount, error) + RevokeUserServiceAccountAccessToken(ctx context.Context, token string) error + RevokeGroupServiceAccountAccessToken(ctx context.Context, token string) error + CreatePipelineProjectTriggerAccessToken(ctx context.Context, path, name string, projectId int, description string, expiresAt *time.Time) (*models.TokenPipelineProjectTrigger, error) + RevokePipelineProjectTriggerAccessToken(ctx context.Context, projectId int, tokenId int) error + CreateProjectDeployToken(ctx context.Context, path string, projectId int, name string, expiresAt *time.Time, scopes []string) (et *models.TokenProjectDeploy, err error) + RevokeProjectDeployToken(ctx context.Context, projectId, deployTokenId int) (err error) + CreateGroupDeployToken(ctx context.Context, path string, groupId int, name string, expiresAt *time.Time, scopes []string) (et *models.TokenGroupDeploy, err error) + RevokeGroupDeployToken(ctx context.Context, groupId, deployTokenId int) (err error) +} From 7030f9037661b2f65fc8df492c44c1204bfafbe1 Mon Sep 17 00:00:00 2001 From: Ilija Matoski Date: Tue, 12 Aug 2025 10:25:18 +0200 Subject: [PATCH 17/17] add comments for some functinos --- internal/gitlab/ctx.go | 10 ++++++++++ internal/utils/calculate_gitlab_ttl.go | 6 ++++++ internal/utils/convert_to_int.go | 6 ++++++ internal/utils/ctx_http_client.go | 11 +++++++++++ internal/utils/ctx_time.go | 11 +++++++++++ internal/utils/name_tpl.go | 20 ++++++++++++++++++++ internal/utils/to_any.go | 6 ++++++ 7 files changed, 70 insertions(+) diff --git a/internal/gitlab/ctx.go b/internal/gitlab/ctx.go index 4452cc6..0cdd0a8 100644 --- a/internal/gitlab/ctx.go +++ b/internal/gitlab/ctx.go @@ -8,10 +8,20 @@ var ( ctxKeyGitlabClient = contextKey("vpsg-ctx-key-gitlab-client") ) +// ClientNewContext returns a new context.Context that carries the provided Client. +// +// This function embeds the specified GitLab client into the given context, allowing +// it to be retrieved later in the execution flow. It's particularly useful for passing +// around client information across different layers of an application. func ClientNewContext(ctx context.Context, client Client) context.Context { return context.WithValue(ctx, ctxKeyGitlabClient, client) } +// ClientFromContext extracts the GitLab Client from the provided context. +// +// This function attempts to retrieve a Client from the given context. If it was +// not present or if it cannot be asserted as a Client, the returned Client will +// be nil and the boolean will be false. func ClientFromContext(ctx context.Context) (Client, bool) { u, ok := ctx.Value(ctxKeyGitlabClient).(Client) if !ok { diff --git a/internal/utils/calculate_gitlab_ttl.go b/internal/utils/calculate_gitlab_ttl.go index 2ef4f1f..842a399 100644 --- a/internal/utils/calculate_gitlab_ttl.go +++ b/internal/utils/calculate_gitlab_ttl.go @@ -4,6 +4,12 @@ import ( "time" ) +// CalculateGitlabTTL calculates the Time-To-Live (TTL) and expiration time for +// a GitLab-related operation based on a specified duration and start time. +// +// The function ensures that the calculated expiration does not exceed one year +// from the start time. It computes the expiration to be at the midnight +// following the calculated expiration date. func CalculateGitlabTTL(duration time.Duration, start time.Time) (ttl time.Duration, exp time.Time, err error) { start = start.UTC() const D = 24 * time.Hour diff --git a/internal/utils/convert_to_int.go b/internal/utils/convert_to_int.go index 6bb0ac2..6452e14 100644 --- a/internal/utils/convert_to_int.go +++ b/internal/utils/convert_to_int.go @@ -6,6 +6,12 @@ import ( "github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs" ) +// ConvertToInt attempts to convert various numeric types to an int. +// +// This function handles conversions from several numeric types (including int, int8, +// int16, int32, int64, float32, and float64) to a standard int. It utilizes type +// assertion to check the underlying type of the input. If the input is not a supported +// numeric type, it returns an error. func ConvertToInt(num any) (int, error) { switch val := num.(type) { case int: diff --git a/internal/utils/ctx_http_client.go b/internal/utils/ctx_http_client.go index e51f453..c07a61e 100644 --- a/internal/utils/ctx_http_client.go +++ b/internal/utils/ctx_http_client.go @@ -9,10 +9,21 @@ var ( ctxKeyHttpClient = contextKey("vpsg-ctx-key-http-client") ) +// HttpClientNewContext returns a new context.Context that carries the provided http.Client. +// +// This function embeds a given HTTP client into the provided context, allowing it +// to be passed through the application and retrieved later. This is useful for +// managing HTTP client configurations and dependency injection across different +// parts of an application that require HTTP clients. func HttpClientNewContext(ctx context.Context, httpClient *http.Client) context.Context { return context.WithValue(ctx, ctxKeyHttpClient, httpClient) } +// HttpClientFromContext extracts the http.Client from a given context. +// +// This function retrieves an HTTP client that was previously embedded in the context. +// If the context does not contain an HTTP client or it cannot be asserted as an +// *http.Client, the function returns nil and false. func HttpClientFromContext(ctx context.Context) (*http.Client, bool) { u, ok := ctx.Value(ctxKeyHttpClient).(*http.Client) if !ok { diff --git a/internal/utils/ctx_time.go b/internal/utils/ctx_time.go index 79baf96..ca4bf8a 100644 --- a/internal/utils/ctx_time.go +++ b/internal/utils/ctx_time.go @@ -9,10 +9,21 @@ var ( ctxKeyTimeNow = contextKey("vpsg-ctx-key-time-now") ) +// WithStaticTime returns a new context.Context that carries a specific static time. +// +// This function embeds a given time.Time value into the provided context, allowing +// parts of an application to operate with a fixed notion of the current time. This +// can be particularly useful in testing scenarios where you need to control or +// simulate time progression. func WithStaticTime(ctx context.Context, t time.Time) context.Context { return context.WithValue(ctx, ctxKeyTimeNow, t) } +// TimeFromContext extracts a time.Time from the given context. +// +// This function retrieves a time value that was previously embedded in the context. +// If the context does not contain such a time value, it defaults to returning time.Now(), +// effectively providing the current system time. func TimeFromContext(ctx context.Context) time.Time { t, ok := ctx.Value(ctxKeyTimeNow).(time.Time) if !ok { diff --git a/internal/utils/name_tpl.go b/internal/utils/name_tpl.go index 83898c6..646abb1 100644 --- a/internal/utils/name_tpl.go +++ b/internal/utils/name_tpl.go @@ -34,12 +34,26 @@ var tplFuncMap = template.FuncMap{ "timeNowFormat": timeNowFormat, } +// TokenNameData defines an interface for objects that contain a token name and +// methods for obtaining data relevant to token-based operations. +// +// This interface provides a contract for structures that need to offer +// token name data and conversion capabilities. It is used to ensure consistent +// handling of token names and associated logic. type TokenNameData interface { + // GetName returns the token's name as a string GetName() string + // LogicalResponseData returns a map containing relevant data that can be used in template operations or logical evaluations LogicalResponseData() map[string]any + // IsNil returns a boolean indicating whether the instance is considered nil or invalid IsNil() bool } +// ValidateTokenNameName validates the template syntax of a token name. +// +// This function checks if the provided TokenNameData instance is non-nil and executes +// basic validation of the token name's syntax by parsing it as a template. This helps +// ensure the token name format adheres to expected patterns and contains no syntax errors. func ValidateTokenNameName(role TokenNameData) (err error) { if role == nil || role.IsNil() { return fmt.Errorf("role: %w", errs.ErrNilValue) @@ -48,6 +62,12 @@ func ValidateTokenNameName(role TokenNameData) (err error) { return err } +// TokenName generates a token name by executing the template defined in TokenNameData. +// +// This function retrieves the template string from the TokenNameData, parses it, and +// then executes it while substituting placeholders with the logical response data +// provided by the token role. An additional "unix_timestamp_utc" field is added to the +// data map, representing the current UTC Unix timestamp. func TokenName(role TokenNameData) (name string, err error) { if role == nil || role.IsNil() { return "", fmt.Errorf("role: %w", errs.ErrNilValue) diff --git a/internal/utils/to_any.go b/internal/utils/to_any.go index b97ed63..3af9bae 100644 --- a/internal/utils/to_any.go +++ b/internal/utils/to_any.go @@ -1,5 +1,11 @@ package utils +// ToAny converts a slice of values of type int or string to a slice of empty interfaces (any). +// +// This function is a generic utility that allows for the conversion of a variadic list +// of integers or strings into a slice of empty interfaces (`[]any`). This is particularly +// useful when you need to pass mixed-type values around, or when API requirements dictate +// an `any` type. func ToAny[T int | string](values ...T) (ret []any) { ret = make([]any, 0, len(values)) for _, value := range values {