Skip to content

Commit 97be25b

Browse files
committed
moved token scope to token pkg
1 parent 7a0efe0 commit 97be25b

28 files changed

+315
-310
lines changed

gitlab_client_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ func TestGitlabClient_CreateAccessToken_And_Revoke(t *testing.T) {
257257
"example",
258258
"name",
259259
timeExpiresAt,
260-
[]string{gitlab.TokenScopeReadApi.String()},
260+
[]string{token2.ScopeReadApi.String()},
261261
gitlab.AccessLevelGuestPermissions,
262262
)
263263
require.NoError(t, err)
@@ -271,7 +271,7 @@ func TestGitlabClient_CreateAccessToken_And_Revoke(t *testing.T) {
271271
"example/example",
272272
"name",
273273
timeExpiresAt,
274-
[]string{gitlab.TokenScopeReadApi.String()},
274+
[]string{token2.ScopeReadApi.String()},
275275
gitlab.AccessLevelDeveloperPermissions,
276276
)
277277
require.NoError(t, err)
@@ -286,7 +286,7 @@ func TestGitlabClient_CreateAccessToken_And_Revoke(t *testing.T) {
286286
1,
287287
"name",
288288
timeExpiresAt,
289-
[]string{gitlab.TokenScopeReadApi.String()},
289+
[]string{token2.ScopeReadApi.String()},
290290
)
291291
require.NoError(t, err)
292292
require.NotNil(t, patToken)

internal/errs/errs.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,8 @@ var (
1717

1818
// ErrBackendNotConfigured represents an error when trying to use a backend that hasn't been properly configured
1919
ErrBackendNotConfigured = errors.New("backend not configured")
20+
21+
ErrUnknownTokenType = errors.New("unknown token type")
22+
23+
ErrUnknownTokenScope = errors.New("unknown token scope")
2024
)

internal/token/scope.go

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package token
2+
3+
import (
4+
"fmt"
5+
"slices"
6+
7+
"github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs"
8+
)
9+
10+
type Scope string
11+
12+
const (
13+
// 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
14+
ScopeApi = Scope("api")
15+
// ScopeReadApi grants read access to the scoped group and related project API, including the Package Registry
16+
ScopeReadApi = Scope("read_api")
17+
// ScopeReadRegistry grants read access (pull) to the Container Registry images if any project within expected group is private and authorization is required.
18+
ScopeReadRegistry = Scope("read_registry")
19+
// ScopeWriteRegistry grants write access (push) to the Container Registry.
20+
ScopeWriteRegistry = Scope("write_registry")
21+
// ScopeReadRepository grants read access (pull) to the Container Registry images if any project within expected group is private and authorization is required
22+
ScopeReadRepository = Scope("read_repository")
23+
// ScopeWriteRepository grants read and write access (pull and push) to all repositories within expected group
24+
ScopeWriteRepository = Scope("write_repository")
25+
26+
// ScopeReadPackageRegistry Allows read-only access to the package registry.
27+
ScopeReadPackageRegistry = Scope("read_package_registry")
28+
// ScopeWritePackageRegistry Allows read and write access to the package registry.
29+
ScopeWritePackageRegistry = Scope("write_package_registry")
30+
31+
// ScopeCreateRunner grants permission to create runners in expected group
32+
ScopeCreateRunner = Scope("create_runner")
33+
// ScopeManageRunner grants permission to manage runners in expected group
34+
ScopeManageRunner = Scope("manage_runner")
35+
36+
// 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.
37+
ScopeReadUser = Scope("read_user")
38+
// ScopeSudo grants permission to perform API actions as any user in the system, when authenticated as an administrator.
39+
ScopeSudo = Scope("sudo")
40+
// ScopeAdminMode grants permission to perform API actions as an administrator, when Admin Mode is enabled.
41+
ScopeAdminMode = Scope("admin_mode")
42+
43+
// 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.
44+
ScopeAiFeatures = Scope("ai_features")
45+
// ScopeK8SProxy grants permission to perform Kubernetes API calls using the agent for Kubernetes.
46+
ScopeK8SProxy = Scope("k8s_proxy")
47+
// ScopeReadServicePing grant access to download Service Ping payload through the API when authenticated as an admin use.
48+
ScopeReadServicePing = Scope("read_service_ping")
49+
50+
// ScopeSelfRotate grants permission to rotate this token using the personal access token API. Does not allow rotation of other tokens.
51+
ScopeSelfRotate = Scope("self_rotate")
52+
// 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.
53+
ScopeReadVirtualRegistry = Scope("read_virtual_registry")
54+
// 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.
55+
ScopeWriteVirtualRegistry = Scope("write_virtual_registry")
56+
57+
ScopeUnknown = Scope("")
58+
)
59+
60+
var (
61+
62+
// ValidPersonalTokenScopes defines the actions you can perform when you authenticate with a project access token.
63+
ValidPersonalTokenScopes = []string{
64+
ScopeApi.String(),
65+
ScopeReadUser.String(),
66+
ScopeReadApi.String(),
67+
ScopeReadRepository.String(),
68+
ScopeWriteRepository.String(),
69+
ScopeReadRegistry.String(),
70+
ScopeWriteRegistry.String(),
71+
ScopeReadVirtualRegistry.String(),
72+
ScopeWriteVirtualRegistry.String(),
73+
ScopeSudo.String(),
74+
ScopeAdminMode.String(),
75+
ScopeCreateRunner.String(),
76+
ScopeManageRunner.String(),
77+
ScopeAiFeatures.String(),
78+
ScopeK8SProxy.String(),
79+
ScopeSelfRotate.String(),
80+
ScopeReadServicePing.String(),
81+
}
82+
83+
ValidProjectTokenScopes = []string{
84+
ScopeApi.String(),
85+
ScopeReadApi.String(),
86+
ScopeReadRegistry.String(),
87+
ScopeWriteRegistry.String(),
88+
ScopeReadRepository.String(),
89+
ScopeWriteRepository.String(),
90+
ScopeCreateRunner.String(),
91+
ScopeManageRunner.String(),
92+
ScopeAiFeatures.String(),
93+
ScopeK8SProxy.String(),
94+
ScopeSelfRotate.String(),
95+
}
96+
97+
ValidGroupTokenScopes = []string{
98+
ScopeApi.String(),
99+
ScopeReadApi.String(),
100+
ScopeReadRegistry.String(),
101+
ScopeWriteRegistry.String(),
102+
ScopeReadVirtualRegistry.String(),
103+
ScopeWriteVirtualRegistry.String(),
104+
ScopeReadRepository.String(),
105+
ScopeWriteRepository.String(),
106+
ScopeCreateRunner.String(),
107+
ScopeManageRunner.String(),
108+
ScopeAiFeatures.String(),
109+
ScopeK8SProxy.String(),
110+
ScopeSelfRotate.String(),
111+
}
112+
113+
ValidUserServiceAccountTokenScopes = ValidPersonalTokenScopes
114+
115+
ValidGroupServiceAccountTokenScopes = ValidGroupTokenScopes
116+
117+
ValidPipelineProjectTokenScopes []string
118+
119+
ValidProjectDeployTokenScopes = []string{
120+
ScopeReadRepository.String(),
121+
ScopeReadRegistry.String(),
122+
ScopeWriteRegistry.String(),
123+
ScopeReadVirtualRegistry.String(),
124+
ScopeWriteVirtualRegistry.String(),
125+
ScopeReadPackageRegistry.String(),
126+
ScopeWritePackageRegistry.String(),
127+
}
128+
129+
ValidGroupDeployTokenScopes = []string{
130+
ScopeReadRepository.String(),
131+
ScopeReadRegistry.String(),
132+
ScopeWriteRegistry.String(),
133+
ScopeReadVirtualRegistry.String(),
134+
ScopeWriteVirtualRegistry.String(),
135+
ScopeReadPackageRegistry.String(),
136+
ScopeWritePackageRegistry.String(),
137+
}
138+
)
139+
140+
func (i Scope) String() string {
141+
return string(i)
142+
}
143+
144+
func (i Scope) Value() string {
145+
return i.String()
146+
}
147+
148+
func ScopeParse(value string) (Scope, error) {
149+
if slices.Contains(ValidGroupTokenScopes, value) ||
150+
slices.Contains(ValidPipelineProjectTokenScopes, value) ||
151+
slices.Contains(ValidGroupDeployTokenScopes, value) ||
152+
slices.Contains(ValidProjectDeployTokenScopes, value) ||
153+
slices.Contains(ValidPersonalTokenScopes, value) ||
154+
slices.Contains(ValidProjectTokenScopes, value) ||
155+
slices.Contains(ValidUserServiceAccountTokenScopes, value) ||
156+
slices.Contains(ValidGroupServiceAccountTokenScopes, value) {
157+
return Scope(value), nil
158+
}
159+
return ScopeUnknown, fmt.Errorf("failed to parse '%s': %w", value, errs.ErrUnknownTokenScope)
160+
}

internal/token/scope_test.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
//go:build unit
2+
3+
package token_test
4+
5+
import (
6+
"testing"
7+
8+
"github.com/stretchr/testify/assert"
9+
10+
"github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs"
11+
"github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token"
12+
)
13+
14+
func TestTokenScope(t *testing.T) {
15+
var tests = []struct {
16+
expected token.Scope
17+
input string
18+
err bool
19+
}{
20+
{
21+
expected: token.ScopeApi,
22+
input: token.ScopeApi.String(),
23+
},
24+
{
25+
expected: token.ScopeReadApi,
26+
input: token.ScopeReadApi.String(),
27+
},
28+
{
29+
expected: token.ScopeReadRegistry,
30+
input: token.ScopeReadRegistry.String(),
31+
},
32+
{
33+
expected: token.ScopeWriteRegistry,
34+
input: token.ScopeWriteRegistry.String(),
35+
},
36+
{
37+
expected: token.ScopeReadRepository,
38+
input: token.ScopeReadRepository.String(),
39+
},
40+
{
41+
expected: token.ScopeWriteRepository,
42+
input: token.ScopeWriteRepository.String(),
43+
},
44+
{
45+
expected: token.ScopeCreateRunner,
46+
input: token.ScopeCreateRunner.String(),
47+
},
48+
{
49+
expected: token.ScopeReadUser,
50+
input: token.ScopeReadUser.String(),
51+
},
52+
{
53+
expected: token.ScopeSudo,
54+
input: token.ScopeSudo.String(),
55+
},
56+
{
57+
expected: token.ScopeAdminMode,
58+
input: token.ScopeAdminMode.String(),
59+
},
60+
{
61+
expected: token.ScopeReadPackageRegistry,
62+
input: token.ScopeReadPackageRegistry.String(),
63+
},
64+
{
65+
expected: token.ScopeWritePackageRegistry,
66+
input: token.ScopeWritePackageRegistry.String(),
67+
},
68+
{
69+
expected: token.ScopeUnknown,
70+
input: "what",
71+
err: true,
72+
},
73+
{
74+
expected: token.ScopeUnknown,
75+
input: "unknown",
76+
err: true,
77+
},
78+
}
79+
80+
for _, test := range tests {
81+
t.Logf("assert parse(%s) = %s (err: %v)", test.input, test.expected, test.err)
82+
val, err := token.ScopeParse(test.input)
83+
assert.EqualValues(t, test.expected, val)
84+
assert.EqualValues(t, test.expected.Value(), test.expected.String())
85+
if test.err {
86+
assert.ErrorIs(t, err, errs.ErrUnknownTokenScope)
87+
} else {
88+
assert.NoError(t, err)
89+
}
90+
}
91+
}

internal/token/type.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package token
22

33
import (
4-
"errors"
54
"fmt"
65
"slices"
6+
7+
"github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs"
78
)
89

910
type Type string
@@ -22,8 +23,6 @@ const (
2223
)
2324

2425
var (
25-
ErrUnknownTokenType = errors.New("unknown token type")
26-
2726
ValidTokenTypes = []string{
2827
TypePersonal.String(),
2928
TypeProject.String(),
@@ -48,5 +47,5 @@ func TypeParse(value string) (Type, error) {
4847
if slices.Contains(ValidTokenTypes, value) {
4948
return Type(value), nil
5049
}
51-
return TypeUnknown, fmt.Errorf("failed to parse '%s': %w", value, ErrUnknownTokenType)
50+
return TypeUnknown, fmt.Errorf("failed to parse '%s': %w", value, errs.ErrUnknownTokenType)
5251
}

internal/token/type_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
"github.com/stretchr/testify/assert"
99

10+
"github.com/ilijamt/vault-plugin-secrets-gitlab/internal/errs"
1011
"github.com/ilijamt/vault-plugin-secrets-gitlab/internal/token"
1112
)
1213

@@ -66,7 +67,7 @@ func TestTokenType(t *testing.T) {
6667
assert.EqualValues(t, test.expected, val)
6768
assert.EqualValues(t, test.expected.Value(), test.expected.String())
6869
if test.err {
69-
assert.ErrorIs(t, err, token.ErrUnknownTokenType)
70+
assert.ErrorIs(t, err, errs.ErrUnknownTokenType)
7071
} else {
7172
assert.NoError(t, err)
7273
}

name_tpl_rand_string_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func TestTokenNameGenerator_RandString(t *testing.T) {
1919
TTL: time.Hour,
2020
Path: "/path",
2121
Name: "{{ randHexString 8 }}",
22-
Scopes: []string{g.TokenScopeApi.String()},
22+
Scopes: []string{token.ScopeApi.String()},
2323
AccessLevel: g.AccessLevelNoPermissions,
2424
TokenType: token.TypePersonal,
2525
GitlabRevokesTokens: false,

name_tpl_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func TestTokenNameGenerator(t *testing.T) {
2828
TTL: time.Hour,
2929
Path: "/path",
3030
Name: "{{ .role_name",
31-
Scopes: []string{g.TokenScopeApi.String()},
31+
Scopes: []string{token.ScopeApi.String()},
3232
AccessLevel: g.AccessLevelNoPermissions,
3333
TokenType: token.TypePersonal,
3434
GitlabRevokesTokens: true,
@@ -44,7 +44,7 @@ func TestTokenNameGenerator(t *testing.T) {
4444
TTL: time.Hour,
4545
Path: "/path",
4646
Name: "{{ .role_name }}-{{ .token_type }}-access-token-{{ yesNoBool .gitlab_revokes_token }}",
47-
Scopes: []string{g.TokenScopeApi.String()},
47+
Scopes: []string{token.ScopeApi.String()},
4848
AccessLevel: g.AccessLevelNoPermissions,
4949
TokenType: token.TypePersonal,
5050
GitlabRevokesTokens: true,
@@ -60,7 +60,7 @@ func TestTokenNameGenerator(t *testing.T) {
6060
TTL: time.Hour,
6161
Path: "/path",
6262
Name: "{{ .role_name }}-{{ .token_type }}-{{ stringsJoin .scopes \"-\" }}-{{ yesNoBool .gitlab_revokes_token }}",
63-
Scopes: []string{g.TokenScopeApi.String(), g.TokenScopeSudo.String()},
63+
Scopes: []string{token.ScopeApi.String(), token.ScopeSudo.String()},
6464
AccessLevel: g.AccessLevelNoPermissions,
6565
TokenType: token.TypePersonal,
6666
GitlabRevokesTokens: false,
@@ -76,7 +76,7 @@ func TestTokenNameGenerator(t *testing.T) {
7676
TTL: time.Hour,
7777
Path: "/path",
7878
Name: "{{ .role_name }}-{{ .token_type }}-{{ timeNowFormat \"2006-01\" }}",
79-
Scopes: []string{g.TokenScopeApi.String(), g.TokenScopeSudo.String()},
79+
Scopes: []string{token.ScopeApi.String(), token.ScopeSudo.String()},
8080
AccessLevel: g.AccessLevelNoPermissions,
8181
TokenType: token.TypePersonal,
8282
GitlabRevokesTokens: false,

name_tpl_unix_timestamp_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func TestTokenNameGenerator_UnixTimeStamp(t *testing.T) {
2121
TTL: time.Hour,
2222
Path: "/path",
2323
Name: "{{ .unix_timestamp_utc }}",
24-
Scopes: []string{g.TokenScopeApi.String()},
24+
Scopes: []string{token.ScopeApi.String()},
2525
AccessLevel: g.AccessLevelNoPermissions,
2626
TokenType: token.TypePersonal,
2727
GitlabRevokesTokens: false,

0 commit comments

Comments
 (0)