Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for groups job token #1894

Merged
merged 2 commits into from
Mar 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
98 changes: 98 additions & 0 deletions job_token_scope.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,101 @@ func (j *JobTokenScopeService) RemoveProjectFromJobScopeAllowList(pid interface{

return j.client.Do(req, nil)
}

// JobTokenAllowlistItem represents a single job token allowlist item.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/project_job_token_scopes.html
type JobTokenAllowlistItem struct {
SourceProjectID int `json:"source_project_id"`
TargetGroupID int `json:"target_group_id"`
}

// GetJobTokenAllowlistGroupsOptions represents the available
// GetJobTokenAllowlistGroups() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_job_token_scopes.html#get-a-projects-cicd-job-token-allowlist-of-groups
type GetJobTokenAllowlistGroupsOptions struct {
ListOptions
}

// GetJobTokenAllowListGroups fetches the CI/CD job token allowlist groups
// (job token scopes) of a project.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_job_token_scopes.html#get-a-projects-cicd-job-token-allowlist-of-groups
func (j *JobTokenScopeService) GetJobTokenAllowlistGroups(pid interface{}, opt *GetJobTokenAllowlistGroupsOptions, options ...RequestOptionFunc) ([]*Group, *Response, error) {
project, err := parseID(pid)
if err != nil {
return nil, nil, err
}
u := fmt.Sprintf(`projects/%s/job_token_scope/groups_allowlist`, PathEscape(project))

req, err := j.client.NewRequest(http.MethodGet, u, opt, options)
if err != nil {
return nil, nil, err
}

var ps []*Group
resp, err := j.client.Do(req, &ps)
if err != nil {
return nil, resp, err
}

return ps, resp, nil
}

// AddGroupToJobTokenAllowlistOptions represents the available
// AddGroupToJobTokenAllowlist() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_job_token_scopes.html#add-a-group-to-a-cicd-job-token-allowlist
type AddGroupToJobTokenAllowlistOptions struct {
TargetGroupID *int `url:"target_group_id,omitempty" json:"target_group_id,omitempty"`
}

// AddProjectToJobScopeGroupsAllowList adds a new group to a project's job token
// inbound groups allow list.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_job_token_scopes.html#add-a-group-to-a-cicd-job-token-allowlist
func (j *JobTokenScopeService) AddGroupToJobTokenAllowlist(pid interface{}, opt *AddGroupToJobTokenAllowlistOptions, options ...RequestOptionFunc) (*JobTokenAllowlistItem, *Response, error) {
project, err := parseID(pid)
if err != nil {
return nil, nil, err
}
u := fmt.Sprintf(`projects/%s/job_token_scope/groups_allowlist`, PathEscape(project))

req, err := j.client.NewRequest(http.MethodPost, u, opt, options)
if err != nil {
return nil, nil, err
}

jt := new(JobTokenAllowlistItem)
resp, err := j.client.Do(req, jt)
if err != nil {
return nil, resp, err
}

return jt, resp, nil
}

// RemoveGroupFromJopTokenAllowlist removes a group from a project's job
// token inbound groups allow list.
//
// GitLab API docs:
// https://docs.gitlab.com/ee/api/project_job_token_scopes.html#remove-a-group-from-a-cicd-job-token-allowlist
func (j *JobTokenScopeService) RemoveGroupFromJobTokenAllowlist(pid interface{}, targetGroup int, options ...RequestOptionFunc) (*Response, error) {
project, err := parseID(pid)
if err != nil {
return nil, err
}
u := fmt.Sprintf(`projects/%s/job_token_scope/groups_allowlist/%d`, PathEscape(project), targetGroup)

req, err := j.client.NewRequest(http.MethodDelete, u, nil, options)
if err != nil {
return nil, err
}

return j.client.Do(req, nil)
}
97 changes: 97 additions & 0 deletions job_token_scope_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,100 @@ func TestRemoveProjectFromJobScopeAllowList(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, 204, resp.StatusCode)
}

// This tests that when calling the GetJobTokenAllowlistGroups, we get a list
// of groups back. There isn't a "deep" test with every attribute specified,
// because the object returned is a *Group object, which is already tested in
// groups.go.
func TestGetJobTokenAllowlistGroups(t *testing.T) {
mux, client := setup(t)

// Handle project ID 1, and print a result of two groups
mux.HandleFunc("/api/v4/projects/1/job_token_scope/groups_allowlist", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodGet)

// Print on the response
fmt.Fprint(w, `[{"id":1},{"id":2}]`)
})

want := []*Group{{ID: 1}, {ID: 2}}
groups, _, err := client.JobTokenScope.GetJobTokenAllowlistGroups(
1,
&GetJobTokenAllowlistGroupsOptions{},
)

assert.NoError(t, err)
assert.Equal(t, want, groups)
}

func TestAddGroupToJobTokenAllowlist(t *testing.T) {
mux, client := setup(t)

mux.HandleFunc("/api/v4/projects/1/job_token_scope/groups_allowlist", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodPost)

// Read the request to determine which target group is passed in
body, err := io.ReadAll(r.Body)
if err != nil {
t.Fatalf("JobTokenScope.AddGroupToJobTokenAllowlist failed to read body")
}

// Parse to object to ensure it's sent on the request appropriately.
var createTokenRequest AddGroupToJobTokenAllowlistOptions
err = json.Unmarshal(body, &createTokenRequest)
if err != nil {
t.Fatalf("JobTokenScope.AddGroupToJobTokenAllowlist failed to unmarshal body: %v", err)
}

// Ensure we provide the proper response
w.WriteHeader(http.StatusCreated)

// Print on the response with the proper target group
fmt.Fprintf(w, `{
"source_project_id": 1,
"target_group_id": %d
}`, *createTokenRequest.TargetGroupID)
})

want := &JobTokenAllowlistItem{
SourceProjectID: 1,
TargetGroupID: 2,
}

addTokenResponse, resp, err := client.JobTokenScope.AddGroupToJobTokenAllowlist(
1,
&AddGroupToJobTokenAllowlistOptions{TargetGroupID: Ptr(2)},
)
assert.NoError(t, err)
assert.Equal(t, want, addTokenResponse)
assert.Equal(t, 201, resp.StatusCode)
}

func TestRemoveGroupFromJobTokenAllowlist(t *testing.T) {
mux, client := setup(t)

mux.HandleFunc("/api/v4/projects/1/job_token_scope/groups_allowlist/2", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodDelete)

// Read the request to determine which target group is passed in
body, err := io.ReadAll(r.Body)
if err != nil {
t.Fatalf("JobTokenScope.RemoveGroupFromJobTokenAllowlist failed to read body")
}

// The body should be empty since all attributes are passed in the path
if body != nil && string(body) != "" {
t.Fatalf("JobTokenScope.RemoveGroupFromJobTokenAllowlist failed to unmarshal body: %v", err)
}

// Ensure we provide the proper response
w.WriteHeader(http.StatusNoContent)

// Print an empty body, since that's what the API provides.
fmt.Fprint(w, "")
})

resp, err := client.JobTokenScope.RemoveGroupFromJobTokenAllowlist(1, 2)
assert.NoError(t, err)
assert.Equal(t, 204, resp.StatusCode)
}