diff --git a/example/actionpermissions/main.go b/example/actionpermissions/main.go new file mode 100644 index 0000000000..a84a8e5474 --- /dev/null +++ b/example/actionpermissions/main.go @@ -0,0 +1,80 @@ +// Copyright 2022 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// The actionpermissions command utilizes go-github as a cli tool for +// changing GitHub Actions related permission settings for a repository. +package main + +import ( + "context" + "flag" + "fmt" + "log" + "os" + + "github.com/google/go-github/v43/github" + "golang.org/x/oauth2" +) + +var ( + name = flag.String("name", "", "repo to change Actions permissions.") + owner = flag.String("owner", "", "owner of targeted repo.") +) + +func main() { + flag.Parse() + token := os.Getenv("GITHUB_AUTH_TOKEN") + if token == "" { + log.Fatal("Unauthorized: No token present") + } + if *name == "" { + log.Fatal("No name: repo name must be given") + } + if *owner == "" { + log.Fatal("No owner: owner of repo must be given") + } + ctx := context.Background() + ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token}) + tc := oauth2.NewClient(ctx, ts) + client := github.NewClient(tc) + + actionsPermissionsRepository, _, err := client.Repositories.GetActionsPermissions(ctx, *owner, *name) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("Current ActionsPermissions %s\n", actionsPermissionsRepository.String()) + + actionsPermissionsRepository = &github.ActionsPermissionsRepository{Enabled: github.Bool(true), AllowedActions: github.String("selected")} + _, _, err = client.Repositories.EditActionsPermissions(ctx, *owner, *name, *actionsPermissionsRepository) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("Current ActionsPermissions %s\n", actionsPermissionsRepository.String()) + + actionsAllowed, _, err := client.Repositories.GetActionsAllowed(ctx, *owner, *name) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("Current ActionsAllowed %s\n", actionsAllowed.String()) + + actionsAllowed = &github.ActionsAllowed{GithubOwnedAllowed: github.Bool(true), VerifiedAllowed: github.Bool(false), PatternsAllowed: []string{"a/b"}} + _, _, err = client.Repositories.EditActionsAllowed(ctx, *owner, *name, *actionsAllowed) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("Current ActionsAllowed %s\n", actionsAllowed.String()) + + actionsPermissionsRepository = &github.ActionsPermissionsRepository{Enabled: github.Bool(true), AllowedActions: github.String("all")} + _, _, err = client.Repositories.EditActionsPermissions(ctx, *owner, *name, *actionsPermissionsRepository) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("Current ActionsPermissions %s\n", actionsPermissionsRepository.String()) +} diff --git a/github/github-accessors.go b/github/github-accessors.go index ce5fa26ad6..cad631db5f 100644 --- a/github/github-accessors.go +++ b/github/github-accessors.go @@ -60,6 +60,30 @@ func (a *ActionsPermissions) GetSelectedActionsURL() string { return *a.SelectedActionsURL } +// GetAllowedActions returns the AllowedActions field if it's non-nil, zero value otherwise. +func (a *ActionsPermissionsRepository) GetAllowedActions() string { + if a == nil || a.AllowedActions == nil { + return "" + } + return *a.AllowedActions +} + +// GetEnabled returns the Enabled field if it's non-nil, zero value otherwise. +func (a *ActionsPermissionsRepository) GetEnabled() bool { + if a == nil || a.Enabled == nil { + return false + } + return *a.Enabled +} + +// GetSelectedActionsURL returns the SelectedActionsURL field if it's non-nil, zero value otherwise. +func (a *ActionsPermissionsRepository) GetSelectedActionsURL() string { + if a == nil || a.SelectedActionsURL == nil { + return "" + } + return *a.SelectedActionsURL +} + // GetURL returns the URL field if it's non-nil, zero value otherwise. func (a *AdminEnforcement) GetURL() string { if a == nil || a.URL == nil { diff --git a/github/github-accessors_test.go b/github/github-accessors_test.go index f0ce54ecea..a796fe0554 100644 --- a/github/github-accessors_test.go +++ b/github/github-accessors_test.go @@ -73,6 +73,36 @@ func TestActionsPermissions_GetSelectedActionsURL(tt *testing.T) { a.GetSelectedActionsURL() } +func TestActionsPermissionsRepository_GetAllowedActions(tt *testing.T) { + var zeroValue string + a := &ActionsPermissionsRepository{AllowedActions: &zeroValue} + a.GetAllowedActions() + a = &ActionsPermissionsRepository{} + a.GetAllowedActions() + a = nil + a.GetAllowedActions() +} + +func TestActionsPermissionsRepository_GetEnabled(tt *testing.T) { + var zeroValue bool + a := &ActionsPermissionsRepository{Enabled: &zeroValue} + a.GetEnabled() + a = &ActionsPermissionsRepository{} + a.GetEnabled() + a = nil + a.GetEnabled() +} + +func TestActionsPermissionsRepository_GetSelectedActionsURL(tt *testing.T) { + var zeroValue string + a := &ActionsPermissionsRepository{SelectedActionsURL: &zeroValue} + a.GetSelectedActionsURL() + a = &ActionsPermissionsRepository{} + a.GetSelectedActionsURL() + a = nil + a.GetSelectedActionsURL() +} + func TestAdminEnforcement_GetURL(tt *testing.T) { var zeroValue string a := &AdminEnforcement{URL: &zeroValue} diff --git a/github/github-stringify_test.go b/github/github-stringify_test.go index c5bbca9d9e..142baa21e4 100644 --- a/github/github-stringify_test.go +++ b/github/github-stringify_test.go @@ -36,6 +36,18 @@ func TestActionsPermissions_String(t *testing.T) { } } +func TestActionsPermissionsRepository_String(t *testing.T) { + v := ActionsPermissionsRepository{ + Enabled: Bool(false), + AllowedActions: String(""), + SelectedActionsURL: String(""), + } + want := `github.ActionsPermissionsRepository{Enabled:false, AllowedActions:"", SelectedActionsURL:""}` + if got := v.String(); got != want { + t.Errorf("ActionsPermissionsRepository.String = %v, want %v", got, want) + } +} + func TestAdminStats_String(t *testing.T) { v := AdminStats{ Issues: &IssueStats{}, diff --git a/github/orgs_actions_allowed.go b/github/orgs_actions_allowed.go index 9032d033b6..687ab2f667 100644 --- a/github/orgs_actions_allowed.go +++ b/github/orgs_actions_allowed.go @@ -10,9 +10,9 @@ import ( "fmt" ) -// ActionsAllowed represents selected actions that are allowed in an organization. +// ActionsAllowed represents selected actions that are allowed. // -// GitHub API docs: https://docs.github.com/en/rest/reference/actions#get-allowed-actions-for-an-organization +// GitHub API docs: https://docs.github.com/en/rest/reference/actions#set-allowed-actions-and-workflows-for-an-organization--parameters type ActionsAllowed struct { GithubOwnedAllowed *bool `json:"github_owned_allowed,omitempty"` VerifiedAllowed *bool `json:"verified_allowed,omitempty"` diff --git a/github/repos_actions_allowed.go b/github/repos_actions_allowed.go new file mode 100644 index 0000000000..2770fcccf6 --- /dev/null +++ b/github/repos_actions_allowed.go @@ -0,0 +1,49 @@ +// Copyright 2022 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "context" + "fmt" +) + +// GetActionsAllowed gets the actions that are allowed in a repository. +// +// GitHub API docs: https://docs.github.com/en/rest/reference/actions#get-allowed-actions-and-workflows-for-a-repository +func (s *RepositoriesService) GetActionsAllowed(ctx context.Context, org, repo string) (*ActionsAllowed, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/actions/permissions/selected-actions", org, repo) + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + actionsAllowed := new(ActionsAllowed) + resp, err := s.client.Do(ctx, req, actionsAllowed) + if err != nil { + return nil, resp, err + } + + return actionsAllowed, resp, nil +} + +// EditActionsAllowed sets the actions that are allowed in a repository. +// +// GitHub API docs: https://docs.github.com/en/rest/reference/actions#set-allowed-actions-and-workflows-for-a-repository +func (s *RepositoriesService) EditActionsAllowed(ctx context.Context, org, repo string, actionsAllowed ActionsAllowed) (*ActionsAllowed, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/actions/permissions/selected-actions", org, repo) + req, err := s.client.NewRequest("PUT", u, actionsAllowed) + if err != nil { + return nil, nil, err + } + + p := new(ActionsAllowed) + resp, err := s.client.Do(ctx, req, p) + if err != nil { + return nil, resp, err + } + + return p, resp, nil +} diff --git a/github/repos_actions_allowed_test.go b/github/repos_actions_allowed_test.go new file mode 100644 index 0000000000..6736f909f9 --- /dev/null +++ b/github/repos_actions_allowed_test.go @@ -0,0 +1,93 @@ +// Copyright 2022 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestRepositoryService_GetActionsAllowed(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/actions/permissions/selected-actions", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{"github_owned_allowed":true, "verified_allowed":false, "patterns_allowed":["a/b"]}`) + }) + + ctx := context.Background() + org, _, err := client.Repositories.GetActionsAllowed(ctx, "o", "r") + if err != nil { + t.Errorf("Repositories.GetActionsAllowed returned error: %v", err) + } + want := &ActionsAllowed{GithubOwnedAllowed: Bool(true), VerifiedAllowed: Bool(false), PatternsAllowed: []string{"a/b"}} + if !cmp.Equal(org, want) { + t.Errorf("Repositories.GetActionsAllowed returned %+v, want %+v", org, want) + } + + const methodName = "GetActionsAllowed" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.GetActionsAllowed(ctx, "\n", "\n") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.GetActionsAllowed(ctx, "o", "r") + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestRepositoriesService_EditActionsAllowed(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + input := &ActionsAllowed{GithubOwnedAllowed: Bool(true), VerifiedAllowed: Bool(false), PatternsAllowed: []string{"a/b"}} + + mux.HandleFunc("/repos/o/r/actions/permissions/selected-actions", func(w http.ResponseWriter, r *http.Request) { + v := new(ActionsAllowed) + json.NewDecoder(r.Body).Decode(v) + + testMethod(t, r, "PUT") + if !cmp.Equal(v, input) { + t.Errorf("Request body = %+v, want %+v", v, input) + } + + fmt.Fprint(w, `{"github_owned_allowed":true, "verified_allowed":false, "patterns_allowed":["a/b"]}`) + }) + + ctx := context.Background() + org, _, err := client.Repositories.EditActionsAllowed(ctx, "o", "r", *input) + if err != nil { + t.Errorf("Repositories.EditActionsAllowed returned error: %v", err) + } + + want := &ActionsAllowed{GithubOwnedAllowed: Bool(true), VerifiedAllowed: Bool(false), PatternsAllowed: []string{"a/b"}} + if !cmp.Equal(org, want) { + t.Errorf("Repositories.EditActionsAllowed returned %+v, want %+v", org, want) + } + + const methodName = "EditActionsAllowed" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.EditActionsAllowed(ctx, "\n", "\n", *input) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.EditActionsAllowed(ctx, "o", "r", *input) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} diff --git a/github/repos_actions_permissions.go b/github/repos_actions_permissions.go new file mode 100644 index 0000000000..bff8c2f5ab --- /dev/null +++ b/github/repos_actions_permissions.go @@ -0,0 +1,62 @@ +// Copyright 2022 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "context" + "fmt" +) + +// ActionsPermissionsRepository represents a policy for repositories and allowed actions in a repository. +// +// GitHub API docs: https://docs.github.com/en/rest/reference/actions#set-github-actions-permissions-for-a-repository--parameters +type ActionsPermissionsRepository struct { + Enabled *bool `json:"enabled,omitempty"` + AllowedActions *string `json:"allowed_actions,omitempty"` + SelectedActionsURL *string `json:"selected_actions_url,omitempty"` +} + +func (a ActionsPermissionsRepository) String() string { + return Stringify(a) +} + +// GetActionsPermissions gets the GitHub Actions permissions policy for repositories and allowed actions in a repository. +// +// GitHub API docs: https://docs.github.com/en/rest/reference/actions#get-github-actions-permissions-for-a-repository +func (s *RepositoriesService) GetActionsPermissions(ctx context.Context, owner, repo string) (*ActionsPermissionsRepository, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/actions/permissions", owner, repo) + req, err := s.client.NewRequest("GET", u, nil) + if err != nil { + return nil, nil, err + } + + permissions := new(ActionsPermissionsRepository) + resp, err := s.client.Do(ctx, req, permissions) + if err != nil { + return nil, resp, err + } + + return permissions, resp, nil +} + +// EditActionsPermissions sets the permissions policy for repositories and allowed actions in a repository. +// +// GitHub API docs: https://docs.github.com/en/rest/reference/actions#set-github-actions-permissions-for-a-repository +func (s *RepositoriesService) EditActionsPermissions(ctx context.Context, owner, repo string, actionsPermissionsRepository ActionsPermissionsRepository) (*ActionsPermissionsRepository, *Response, error) { + u := fmt.Sprintf("repos/%v/%v/actions/permissions", owner, repo) + req, err := s.client.NewRequest("PUT", u, actionsPermissionsRepository) + if err != nil { + return nil, nil, err + } + + permissions := new(ActionsPermissionsRepository) + resp, err := s.client.Do(ctx, req, permissions) + if err != nil { + return nil, resp, err + } + + return permissions, resp, nil +} diff --git a/github/repos_actions_permissions_test.go b/github/repos_actions_permissions_test.go new file mode 100644 index 0000000000..1d6012f62d --- /dev/null +++ b/github/repos_actions_permissions_test.go @@ -0,0 +1,112 @@ +// Copyright 2022 The go-github AUTHORS. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package github + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestRepositoriesService_GetActionsPermissions(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/actions/permissions", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "GET") + fmt.Fprint(w, `{"enabled": true, "allowed_actions": "all"}`) + }) + + ctx := context.Background() + org, _, err := client.Repositories.GetActionsPermissions(ctx, "o", "r") + if err != nil { + t.Errorf("Repositories.GetActionsPermissions returned error: %v", err) + } + want := &ActionsPermissionsRepository{Enabled: Bool(true), AllowedActions: String("all")} + if !cmp.Equal(org, want) { + t.Errorf("Repositories.GetActionsPermissions returned %+v, want %+v", org, want) + } + + const methodName = "GetActionsPermissions" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.GetActionsPermissions(ctx, "\n", "\n") + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.GetActionsPermissions(ctx, "o", "r") + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestRepositoriesService_EditActionsPermissions(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + input := &ActionsPermissionsRepository{Enabled: Bool(true), AllowedActions: String("selected")} + + mux.HandleFunc("/repos/o/r/actions/permissions", func(w http.ResponseWriter, r *http.Request) { + v := new(ActionsPermissionsRepository) + json.NewDecoder(r.Body).Decode(v) + + testMethod(t, r, "PUT") + if !cmp.Equal(v, input) { + t.Errorf("Request body = %+v, want %+v", v, input) + } + + fmt.Fprint(w, `{"enabled": true, "allowed_actions": "selected"}`) + }) + + ctx := context.Background() + org, _, err := client.Repositories.EditActionsPermissions(ctx, "o", "r", *input) + if err != nil { + t.Errorf("Repositories.EditActionsPermissions returned error: %v", err) + } + + want := &ActionsPermissionsRepository{Enabled: Bool(true), AllowedActions: String("selected")} + if !cmp.Equal(org, want) { + t.Errorf("Repositories.EditActionsPermissions returned %+v, want %+v", org, want) + } + + const methodName = "EditActionsPermissions" + testBadOptions(t, methodName, func() (err error) { + _, _, err = client.Repositories.EditActionsPermissions(ctx, "\n", "\n", *input) + return err + }) + + testNewRequestAndDoFailure(t, methodName, client, func() (*Response, error) { + got, resp, err := client.Repositories.EditActionsPermissions(ctx, "o", "r", *input) + if got != nil { + t.Errorf("testNewRequestAndDoFailure %v = %#v, want nil", methodName, got) + } + return resp, err + }) +} + +func TestActionsPermissionsRepository_Marshal(t *testing.T) { + testJSONMarshal(t, &ActionsPermissions{}, "{}") + + u := &ActionsPermissionsRepository{ + Enabled: Bool(true), + AllowedActions: String("all"), + SelectedActionsURL: String("someURL"), + } + + want := `{ + "enabled": true, + "allowed_actions": "all", + "selected_actions_url": "someURL" + }` + + testJSONMarshal(t, u, want) +}